/// <summary> /// Called when the <c>DataContext</c> property of the <see cref="TargetControl"/> has changed. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param> public virtual void OnTargetControlDataContextChanged(object sender, DependencyPropertyValueChangedEventArgs e) { Log.Debug("DataContext of TargetControl '{0}' has changed to '{1}'", TargetControl.GetType().Name, ObjectToStringHelper.ToTypeString(TargetControl.DataContext)); var dataContext = TargetControl.DataContext; if (dataContext == null) { return; } if (BindingHelper.IsSentinelObject(dataContext)) { return; } if (ViewModel == dataContext) { return; } if (dataContext.GetType().IsAssignableFromEx(ViewModelType)) { // Use the view model from the data context, probably set manually ViewModel = (IViewModel)dataContext; } }
/// <summary>7 /// Overridden OnPreRender method. Build data-options and add it into extender target as an data-options attribute. /// </summary> /// <param name="e"></param> protected override void OnPreRender(EventArgs e) { base.OnPreRender(e); if (DesignMode) { return; } var dataOptions = JQueryScriptBuilder.BuildDataOptionsAttribute(this); var targetControl = this.TargetControl as WebControl; var htmlTargetControl = this.TargetControl as HtmlControl; if (targetControl == null && htmlTargetControl == null) { throw new Exception("Target control type must be WebControl or HtmlControl"); } _targetControlType = TargetControl.GetType(); TargetControl.Parent.SetRenderMethodDelegate(RenderTargetControl); var attrs = (targetControl != null) ? (targetControl is CheckBox) ? (targetControl as CheckBox).InputAttributes : targetControl.Attributes : (htmlTargetControl != null) ? htmlTargetControl.Attributes : null; if (attrs != null) { attrs.Add(DataOptionPrefix + _attrControlName, dataOptions); } }
/// <summary> /// Called when the <see cref="TargetControl"/> has just been unloaded. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> /// <remarks> /// This method will call the <see cref="OnTargetControlUnloaded"/> which can be overriden for custom /// behavior. This method is required to protect from duplicate unloaded events. /// </remarks> private void OnTargetControlUnloadedInternal(object sender, UIEventArgs e) { // Don't do this again (another bug in WPF: OnLoaded is called more than OnUnloaded) if (!IsTargetControlLoaded) { return; } InvokeViewLoadEvent(ViewLoadStateEvent.Unloading); IsUnloading = true; //#if !NET // _isFirstLayoutUpdatedAfterUnloadedEvent = true; //#endif Log.Debug("Target control '{0}' is unloaded", TargetControl.GetType().Name); var view = TargetControl as IView; if (view == null) { Log.Warning("Cannot unregister view '{0}' in the view manager because it does not implement IView", TargetControl.GetType().FullName); } else { _viewManager.UnregisterView(view); } IsTargetControlLoaded = false; _isFirstValidationAfterLoaded = true; OnTargetControlUnloaded(sender, e); var targetControlAsIViewModelContainer = TargetControl as IViewModelContainer; if (targetControlAsIViewModelContainer != null) { ViewToViewModelMappingHelper.UninitializeViewToViewModelMappings(targetControlAsIViewModelContainer); } IsUnloading = false; InvokeViewLoadEvent(ViewLoadStateEvent.Unloaded); }
public void ResetDirtyFlag() { ScriptManager.RegisterClientScriptBlock(TargetControl, TargetControl.GetType(), string.Format("{0}_Values_Update", TargetControl.ClientID), string.Format("document.getElementById(\"{0}\").value = \"{1}\";", string.Format("{0}_Values", TargetControl.ClientID), String.Join(",", GetValuesArray())), true); }
/// <summary> /// Subscribes to the parent view model container. /// </summary> private void SubscribeToParentViewModelContainer() { if (!SupportParentViewModelContainers) { return; } if (HasParentViewModelContainer) { return; } _parentViewModelContainer = FindParentByPredicate(TargetControl, o => o is IViewModelContainer) as IViewModelContainer; if (_parentViewModelContainer != null) { Log.Debug("Found the parent view model container '{0}' for '{1}'", _parentViewModelContainer.GetType().Name, TargetControl.GetType().Name); } else { Log.Debug("Couldn't find parent view model container"); } if (_parentViewModelContainer != null) { _parentViewModelContainer.ViewModelChanged += OnParentViewModelContainerViewModelChanged; _parentViewModelContainer.ViewLoading += OnParentViewModelContainerLoading; _parentViewModelContainer.ViewUnloading += OnParentViewModelContainerUnloading; SubscribeToParentViewModel(_parentViewModelContainer.ViewModel); } }
/// <summary> /// Called when the <c>DataContext</c> property of the <see cref="TargetControl"/> has changed. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="DependencyPropertyChangedEventArgs"/> instance containing the event data.</param> public override void OnTargetControlDataContextChanged(object sender, DependencyPropertyValueChangedEventArgs e) { // Fix in WinRT to make sure inner grid is created if (_viewModelGrid == null) { if (TargetControl.Content != null) { CreateViewModelGrid(); } else { Log.Error("Content of control '{0}' is not yet loaded, but the DataContext has changed. The control will bind directly to the DataContext instead of the view model", TargetControl.GetType().FullName); } } // Fix for CTL-307: DataContextChanged is invoked before Unloaded because Parent is set to null var targetControlParent = TargetControl.Parent; if (targetControlParent == null) { return; } base.OnTargetControlDataContextChanged(sender, e); var oldDataContext = e.OldValue; var dataContext = e.NewValue; if (BindingHelper.IsSentinelObject(dataContext)) { return; } if (oldDataContext != null) { ClearWarningsAndErrorsForObject(oldDataContext); } if (!IsUnloading) { UpdateDataContextToUseViewModel(dataContext); } }
/// <summary> /// Called when the <c>DataContext</c> property of the <see cref="TargetControl"/> has changed. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="System.Windows.DependencyPropertyChangedEventArgs"/> instance containing the event data.</param> public override void OnTargetControlDataContextChanged(object sender, DependencyPropertyValueChangedEventArgs e) { // Fix in WinRT to make sure inner grid is created if (_viewModelGrid == null) { if (TargetControl.Content != null) { TargetControl.UnsubscribeFromDependencyProperty("Content", OnTargetControlContentChanged); CreateViewModelGrid(); } else { Log.Error("Content of control '{0}' is not yet loaded, but the DataContext has changed. The control will bind directly to the DataContext instead of the view model", TargetControl.GetType().FullName); } } base.OnTargetControlDataContextChanged(sender, e); var oldDataContext = e.OldValue; var dataContext = e.NewValue; if (BindingHelper.IsSentinelObject(dataContext)) { return; } if (oldDataContext != null) { ClearWarningsAndErrorsForObject(oldDataContext); } UpdateDataContextToUseViewModel(dataContext); }
/// <summary> /// Called when the <see cref="TargetControl"/> has just been loaded. /// </summary> /// <param name="sender">The sender.</param> /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param> /// <remarks> /// This method will call the <see cref="OnTargetControlLoaded"/> which can be overriden for custom /// behavior. This method is required to protect from duplicate loaded events. /// </remarks> private void OnTargetControlLoadedInternal(object sender, UIEventArgs e) { // Don't do this again (another bug in WPF: OnLoaded is called more than OnUnloaded) if (IsTargetControlLoaded) { return; } if (!CanControlBeLoaded) { Log.Debug("Received Loaded or LayoutUpdated, but CanControlBeLoaded is false thus not treating the control as loaded"); return; } Log.Debug("Target control '{0}' is loaded", TargetControl.GetType().Name); InvokeViewLoadEvent(ViewLoadStateEvent.Loading); IsLoading = true; var view = TargetControl as IView; if (view == null) { Log.Warning("Cannot register view '{0}' in the view manager because it does not implement IView", TargetControl.GetType().FullName); } else { _viewManager.RegisterView(view); } IsTargetControlLoaded = true; OnTargetControlLoaded(sender, e); #if !NET // According to the documentation, no visual tree is garantueed in the Loaded event of the user control. // However, as a solution the documentation says you need to manually call ApplyTemplate, so let's do that. // For more info, see http://msdn.microsoft.com/en-us/library/ms596558(vs.95) var targetControl = TargetControl as Control; if (targetControl != null) { (targetControl).ApplyTemplate(); } #endif var targetControlAsIViewModelContainer = TargetControl as IViewModelContainer; if (targetControlAsIViewModelContainer != null) { ViewToViewModelMappingHelper.InitializeViewToViewModelMappings(targetControlAsIViewModelContainer); } var dispatcher = TargetControl.Dispatcher; dispatcher.BeginInvokeIfRequired(() => { if (ViewModel != null) { // Initialize the view model. The view model itself is responsible to prevent double initialization ViewModel.InitializeViewModel(); // Revalidate since the control already initialized the view model before the control // was visible, therefore the WPF engine does not show warnings and errors var viewModelAsViewModelBase = ViewModel as ViewModelBase; if (viewModelAsViewModelBase != null) { viewModelAsViewModelBase.Validate(true, false); } else { ViewModel.ValidateViewModel(true, false); } _isFirstValidationAfterLoaded = true; } }); IsLoading = false; InvokeViewLoadEvent(ViewLoadStateEvent.Loaded); }