/// <summary> /// Called by View whenever its current View.Model changes. Will locate and instantiate the correct view, and set it as the target's Content /// </summary> /// <param name="targetLocation">Thing which View.Model was changed on. Will have its Content set</param> /// <param name="oldValue">Previous value of View.Model</param> /// <param name="newValue">New value of View.Model</param> public virtual void OnModelChanged(DependencyObject targetLocation, object oldValue, object newValue) { if (oldValue == newValue) { return; } if (newValue != null) { logger.Info("View.Model changed for {0} from {1} to {2}", targetLocation, oldValue, newValue); var view = this.CreateAndBindViewForModelIfNecessary(newValue); if (view is Window) { var e = new StyletInvalidViewTypeException(String.Format("s:View.Model=\"...\" tried to show a View of type '{0}', but that View derives from the Window class. " + "Make sure any Views you display using s:View.Model=\"...\" do not derive from Window (use UserControl or similar)", view.GetType().Name)); logger.Error(e); throw e; } View.SetContentProperty(targetLocation, view); } else { logger.Info("View.Model cleared for {0}, from {1}", targetLocation, oldValue); View.SetContentProperty(targetLocation, null); } }
/// <summary> /// Given a ViewModel, create its View, ensure that it's a Window, and set it up /// </summary> /// <param name="viewModel">ViewModel to create the window for</param> /// <param name="isDialog">True if the window will be used as a dialog</param> /// <param name="ownerViewModel">Optionally the ViewModel which owns the view which should own this window</param> /// <returns>Window which was created and set up</returns> protected virtual Window CreateWindow(object viewModel, bool isDialog, IViewAware ownerViewModel) { var view = this.viewManager.CreateAndBindViewForModelIfNecessary(viewModel); var window = view as Window; if (window == null) { var e = new StyletInvalidViewTypeException(String.Format("WindowManager.ShowWindow or .ShowDialog tried to show a View of type '{0}', but that View doesn't derive from the Window class. " + "Make sure any Views you display using WindowManager.ShowWindow or .ShowDialog derive from Window (not UserControl, etc)", view == null ? "(null)" : view.GetType().Name)); logger.Error(e); throw e; } // Only set this it hasn't been set / bound to anything var haveDisplayName = viewModel as IHaveDisplayName; if (haveDisplayName != null && (String.IsNullOrEmpty(window.Title) || window.Title == view.GetType().Name) && BindingOperations.GetBindingBase(window, Window.TitleProperty) == null) { var binding = new Binding("DisplayName") { Mode = BindingMode.TwoWay }; window.SetBinding(Window.TitleProperty, binding); } if (ownerViewModel?.View is Window explicitOwner) { window.Owner = explicitOwner; } else if (isDialog) { var owner = this.InferOwnerOf(window); if (owner != null) { // We can end up in a really weird situation if they try and display more than one dialog as the application's closing // Basically the MainWindow's no long active, so the second dialog chooses the first dialog as its owner... But the first dialog // hasn't yet been shown, so we get an exception ("cannot set owner property to a Window which has not been previously shown"). try { window.Owner = owner; } catch (InvalidOperationException e) { logger.Error(e, "This can occur when the application is closing down"); } } } if (isDialog) { logger.Info("Displaying ViewModel {0} with View {1} as a Dialog", viewModel, window); } else { logger.Info("Displaying ViewModel {0} with View {1} as a Window", viewModel, window); } // If and only if they haven't tried to position the window themselves... // Has to be done after we're attempted to set the owner if (window.WindowStartupLocation == WindowStartupLocation.Manual && Double.IsNaN(window.Top) && Double.IsNaN(window.Left) && BindingOperations.GetBinding(window, Window.TopProperty) == null && BindingOperations.GetBinding(window, Window.LeftProperty) == null) { window.WindowStartupLocation = window.Owner == null ? WindowStartupLocation.CenterScreen : WindowStartupLocation.CenterOwner; } // This gets itself retained by the window, by registering events // ReSharper disable once ObjectCreationAsStatement new WindowConductor(window, viewModel); return(window); }
/// <summary> /// Called by View whenever its current View.Model changes. Will locate and instantiate the correct view, and set it as the target's Content /// </summary> /// <param name="targetLocation">Thing which View.Model was changed on. Will have its Content set</param> /// <param name="oldValue">Previous value of View.Model</param> /// <param name="newValue">New value of View.Model</param> public virtual void OnModelChanged(DependencyObject targetLocation, object oldValue, object newValue) { if (oldValue == newValue) return; if (newValue != null) { logger.Info("View.Model changed for {0} from {1} to {2}", targetLocation, oldValue, newValue); var view = this.CreateAndBindViewForModelIfNecessary(newValue); if (view is Window) { var e = new StyletInvalidViewTypeException(String.Format("s:View.Model=\"...\" tried to show a View of type '{0}', but that View derives from the Window class. " + "Make sure any Views you display using s:View.Model=\"...\" do not derive from Window (use UserControl or similar)", view.GetType().Name)); logger.Error(e); throw e; } View.SetContentProperty(targetLocation, view); } else { logger.Info("View.Model cleared for {0}, from {1}", targetLocation, oldValue); View.SetContentProperty(targetLocation, null); } }
/// <summary> /// Given a ViewModel, create its View, ensure that it's a Window, and set it up /// </summary> /// <param name="viewModel">ViewModel to create the window for</param> /// <param name="isDialog">True if the window will be used as a dialog</param> /// <returns>Window which was created and set up</returns> protected virtual Window CreateWindow(object viewModel, bool isDialog) { var view = this.viewManager.CreateAndBindViewForModelIfNecessary(viewModel); var window = view as Window; if (window == null) { var e = new StyletInvalidViewTypeException(String.Format("WindowManager.ShowWindow or .ShowDialog tried to show a View of type '{0}', but that View doesn't derive from the Window class. " + "Make sure any Views you display using WindowManager.ShowWindow or .ShowDialog derive from Window (not UserControl, etc)", view == null ? "(null)" : view.GetType().Name)); logger.Error(e); throw e; } // Only set this it hasn't been set / bound to anything var haveDisplayName = viewModel as IHaveDisplayName; if (haveDisplayName != null && (String.IsNullOrEmpty(window.Title) || window.Title == view.GetType().Name) && BindingOperations.GetBindingBase(window, Window.TitleProperty) == null) { var binding = new Binding("DisplayName") { Mode = BindingMode.TwoWay }; window.SetBinding(Window.TitleProperty, binding); } if (isDialog) { var owner = this.InferOwnerOf(window); if (owner != null) { // We can end up in a really weird situation if they try and display more than one dialog as the application's closing // Basically the MainWindow's no long active, so the second dialog chooses the first dialog as its owner... But the first dialog // hasn't yet been shown, so we get an exception ("cannot set owner property to a Window which has not been previously shown"). try { window.Owner = owner; } catch (InvalidOperationException e) { logger.Error(e, "This can occur when the application is closing down"); } } logger.Info("Displaying ViewModel {0} with View {1} as a Dialog", viewModel, window); } else { logger.Info("Displaying ViewModel {0} with View {1} as a Window", viewModel, window); } // If and only if they haven't tried to position the window themselves... // Has to be done after we're attempted to set the owner if (window.WindowStartupLocation == WindowStartupLocation.Manual && Double.IsNaN(window.Top) && Double.IsNaN(window.Left)) window.WindowStartupLocation = window.Owner == null ? WindowStartupLocation.CenterScreen : WindowStartupLocation.CenterOwner; // This gets itself retained by the window, by registering events // ReSharper disable once ObjectCreationAsStatement new WindowConductor(window, viewModel); return window; }