From 60aca05dd2b009eb96b386a5003b679525e621de Mon Sep 17 00:00:00 2001 From: Antony Male Date: Thu, 24 Jul 2014 16:39:26 +0100 Subject: [PATCH] Simplify IViewManager, by aligning it to what someone actually wants the ViewManager to do --- Stylet/ViewManager.cs | 40 +++++++++++++----------- Stylet/WindowManager.cs | 4 +-- StyletIntegrationTests/ShellView.xaml | 2 +- StyletUnitTests/ViewManagerTests.cs | 36 ++++++++++++++++------ StyletUnitTests/WindowManagerTests.cs | 44 ++++++++++----------------- 5 files changed, 67 insertions(+), 59 deletions(-) diff --git a/Stylet/ViewManager.cs b/Stylet/ViewManager.cs index 8b147b7..78bbb77 100644 --- a/Stylet/ViewManager.cs +++ b/Stylet/ViewManager.cs @@ -21,18 +21,11 @@ namespace Stylet void OnModelChanged(DependencyObject targetLocation, object oldValue, object newValue); /// - /// Given a ViewModel instance, locate its View type (using LocateViewForModel), instantiates and initializes it + /// Create a View for the given ViewModel, and bind the two together /// - /// ViewModel to locate and instantiate the View for - /// Instantiated and setup view - UIElement CreateAndSetupViewForModel(object model); - - /// - /// Given an instance of a ViewModel and an instance of its View, bind the two together - /// - /// View to bind to the ViewModel - /// ViewModel to bind the View to - void BindViewToModel(UIElement view, object viewModel); + /// ViewModel to create a Veiw for + /// Newly created View, bound to the given ViewModel + UIElement CreateAndBindViewForModel(object model); } /// @@ -61,8 +54,7 @@ namespace Stylet } else { - view = this.CreateAndSetupViewForModel(newValue); - this.BindViewToModel(view, newValue); + view = this.CreateAndBindViewForModel(newValue); } View.SetContentProperty(targetLocation, view); @@ -73,6 +65,20 @@ namespace Stylet } } + /// + /// Create a View for the given ViewModel, and bind the two together + /// + /// ViewModel to create a Veiw for + /// Newly created View, bound to the given ViewModel + public virtual UIElement CreateAndBindViewForModel(object model) + { + // Need to bind before we initialize the view + // Otherwise e.g. the Command bindings get evaluated (by InitializeComponent) but the ActionTarget hasn't been set yet + var view = this.CreateViewForModel(model); + this.BindViewToModel(view, model); + return view; + } + /// /// Given the expected name for a view, locate its type (or throw an exception if a suitable type couldn't be found) /// @@ -102,11 +108,11 @@ namespace Stylet } /// - /// Given a ViewModel instance, locate its View type (using LocateViewForModel), instantiates and initializes it, and binds it to the ViewModel (using BindViewToModel) + /// Given a ViewModel instance, locate its View type (using LocateViewForModel), and instantiates it /// /// ViewModel to locate and instantiate the View for /// Instantiated and setup view - public virtual UIElement CreateAndSetupViewForModel(object model) + protected virtual UIElement CreateViewForModel(object model) { var viewType = this.LocateViewForModel(model.GetType()); @@ -123,12 +129,12 @@ namespace Stylet return view; } - /// + /// /// Given an instance of a ViewModel and an instance of its View, bind the two together /// /// View to bind to the ViewModel /// ViewModel to bind the View to - public virtual void BindViewToModel(UIElement view, object viewModel) + protected virtual void BindViewToModel(UIElement view, object viewModel) { View.SetActionTarget(view, viewModel); diff --git a/Stylet/WindowManager.cs b/Stylet/WindowManager.cs index 8062251..6dd0213 100644 --- a/Stylet/WindowManager.cs +++ b/Stylet/WindowManager.cs @@ -68,13 +68,11 @@ namespace Stylet /// Window which was created and set up protected virtual Window CreateWindow(object viewModel, bool isDialog) { - var view = this.viewManager.CreateAndSetupViewForModel(viewModel); + var view = this.viewManager.CreateAndBindViewForModel(viewModel); var window = view as Window; if (window == null) throw new ArgumentException(String.Format("Tried to show {0} as a window, but it isn't a Window", view == null ? "(null)" : view.GetType().Name)); - this.viewManager.BindViewToModel(window, viewModel); - var haveDisplayName = viewModel as IHaveDisplayName; if (haveDisplayName != null && BindingOperations.GetBindingBase(window, Window.TitleProperty) == null) { diff --git a/StyletIntegrationTests/ShellView.xaml b/StyletIntegrationTests/ShellView.xaml index 0d165a1..5818c6d 100644 --- a/StyletIntegrationTests/ShellView.xaml +++ b/StyletIntegrationTests/ShellView.xaml @@ -6,7 +6,7 @@ - + Result: diff --git a/StyletUnitTests/ViewManagerTests.cs b/StyletUnitTests/ViewManagerTests.cs index e28b8e1..05c8870 100644 --- a/StyletUnitTests/ViewManagerTests.cs +++ b/StyletUnitTests/ViewManagerTests.cs @@ -28,11 +28,24 @@ namespace StyletUnitTests private abstract class AC1 { } private class C1 { } + private class AccessibleViewManager : ViewManager + { + public new UIElement CreateViewForModel(object model) + { + return base.CreateViewForModel(model); + } + + public new void BindViewToModel(UIElement view, object viewModel) + { + base.BindViewToModel(view, viewModel); + } + } + private class CreatingAndBindingViewManager : ViewManager { public UIElement View; public object RequestedModel; - public override UIElement CreateAndSetupViewForModel(object model) + protected override UIElement CreateViewForModel(object model) { this.RequestedModel = model; return this.View; @@ -40,7 +53,7 @@ namespace StyletUnitTests public UIElement BindViewToModelView; public object BindViewtoModelViewModel; - public override void BindViewToModel(UIElement view, object viewModel) + protected override void BindViewToModel(UIElement view, object viewModel) { this.BindViewToModelView = view; this.BindViewtoModelViewModel = viewModel; @@ -156,13 +169,13 @@ namespace StyletUnitTests var viewManager = new LocatingViewManager(); viewManager.LocatedViewType = typeof(I1); - Assert.Throws(() => viewManager.CreateAndSetupViewForModel(new object())); + Assert.Throws(() => viewManager.CreateAndBindViewForModel(new object())); viewManager.LocatedViewType = typeof(AC1); - Assert.Throws(() => viewManager.CreateAndSetupViewForModel(new object())); + Assert.Throws(() => viewManager.CreateAndBindViewForModel(new object())); viewManager.LocatedViewType = typeof(C1); - Assert.Throws(() => viewManager.CreateAndSetupViewForModel(new object())); + Assert.Throws(() => viewManager.CreateAndBindViewForModel(new object())); } [Test] @@ -178,7 +191,7 @@ namespace StyletUnitTests var viewManager = new LocatingViewManager(); viewManager.LocatedViewType = typeof(TestView); - var returnedView = viewManager.CreateAndSetupViewForModel(new object()); + var returnedView = viewManager.CreateAndBindViewForModel(new object()); Assert.True(view.InitializeComponentCalled); Assert.AreEqual(view, returnedView); @@ -197,7 +210,7 @@ namespace StyletUnitTests var viewManager = new LocatingViewManager(); viewManager.LocatedViewType = typeof(UIElement); - var returnedView = viewManager.CreateAndSetupViewForModel(new object()); + var returnedView = viewManager.CreateAndBindViewForModel(new object()); Assert.AreEqual(view, returnedView); } @@ -207,7 +220,8 @@ namespace StyletUnitTests { var view = new UIElement(); var model = new object(); - this.viewManager.BindViewToModel(view, model); + var viewManager = new AccessibleViewManager(); + viewManager.BindViewToModel(view, model); Assert.AreEqual(model, View.GetActionTarget(view)); } @@ -217,7 +231,8 @@ namespace StyletUnitTests { var view = new FrameworkElement(); var model = new object(); - this.viewManager.BindViewToModel(view, model); + var viewManager = new AccessibleViewManager(); + viewManager.BindViewToModel(view, model); Assert.AreEqual(model, view.DataContext); } @@ -227,7 +242,8 @@ namespace StyletUnitTests { var view = new UIElement(); var model = new Mock(); - this.viewManager.BindViewToModel(view, model.Object); + var viewManager = new AccessibleViewManager(); + viewManager.BindViewToModel(view, model.Object); model.Verify(x => x.AttachView(view)); } diff --git a/StyletUnitTests/WindowManagerTests.cs b/StyletUnitTests/WindowManagerTests.cs index eecf21b..7fa528b 100644 --- a/StyletUnitTests/WindowManagerTests.cs +++ b/StyletUnitTests/WindowManagerTests.cs @@ -61,7 +61,7 @@ namespace StyletUnitTests public void CreateWindowAsksViewManagerForView() { var model = new object(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model)).Verifiable(); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model)).Verifiable(); // Don't care if this throws - that's OK try { this.windowManager.CreateWindow(model, false); } catch (Exception) { } @@ -72,28 +72,16 @@ namespace StyletUnitTests public void CreateWindowThrowsIfViewIsntAWindow() { var model = new object(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model)).Returns(new UIElement()); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model)).Returns(new UIElement()); Assert.Throws(() => this.windowManager.CreateWindow(model, false)); } - [Test] - public void CreateWindowBindsViewToModel() - { - var model = new object(); - var window = new Window(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model)).Returns(window); - - this.windowManager.CreateWindow(model, false); - - this.viewManager.Verify(x => x.BindViewToModel(window, model)); - } - [Test] public void CreateWindowSetsUpTitleBindingIfViewModelIsIHaveDisplayName() { var model = new Screen(); var window = new Window(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model)).Returns(window); this.windowManager.CreateWindow(model, false); @@ -106,7 +94,7 @@ namespace StyletUnitTests public void CreateWindowActivatesViewModel() { var model = new Mock(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(new Window()); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(new Window()); this.windowManager.CreateWindow(model.Object, false); model.Verify(x => x.Activate()); } @@ -116,7 +104,7 @@ namespace StyletUnitTests { var model = new Mock(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(window); this.windowManager.CreateWindow(model.Object, false); window.WindowState = WindowState.Maximized; window.OnStateChanged(EventArgs.Empty); @@ -128,7 +116,7 @@ namespace StyletUnitTests { var model = new Mock(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(window); this.windowManager.CreateWindow(model.Object, false); window.WindowState = WindowState.Normal; window.OnStateChanged(EventArgs.Empty); @@ -140,7 +128,7 @@ namespace StyletUnitTests { var model = new Mock(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(window); this.windowManager.CreateWindow(model.Object, false); window.WindowState = WindowState.Minimized; window.OnStateChanged(EventArgs.Empty); @@ -152,7 +140,7 @@ namespace StyletUnitTests { var model = new Screen(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model)).Returns(window); this.windowManager.CreateWindow(model, false); window.OnClosing(new CancelEventArgs(true)); } @@ -162,7 +150,7 @@ namespace StyletUnitTests { var model = new Mock(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(window); this.windowManager.CreateWindow(model.Object, false); model.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(false)); var ea = new CancelEventArgs(); @@ -175,7 +163,7 @@ namespace StyletUnitTests { var model = new Mock(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(window); this.windowManager.CreateWindow(model.Object, false); model.Setup(x => x.CanCloseAsync()).Returns(Task.FromResult(true)); var ea = new CancelEventArgs(); @@ -188,7 +176,7 @@ namespace StyletUnitTests { var model = new Mock(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(window); this.windowManager.CreateWindow(model.Object, false); model.Setup(x => x.CanCloseAsync()).Returns(Task.Delay(1).ContinueWith(t => false)); var ea = new CancelEventArgs(); @@ -201,7 +189,7 @@ namespace StyletUnitTests { var model = new Mock(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(window); this.windowManager.CreateWindow(model.Object, false); model.Setup(x => x.CanCloseAsync()).Returns(Task.Delay(1).ContinueWith(t => true)); var ea = new CancelEventArgs(); @@ -214,7 +202,7 @@ namespace StyletUnitTests { var model = new Mock(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(window); this.windowManager.CreateWindow(model.Object, false); var tcs = new TaskCompletionSource(); model.Setup(x => x.CanCloseAsync()).Returns(tcs.Task); @@ -234,7 +222,7 @@ namespace StyletUnitTests { var model = new Screen(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model)).Returns(window); this.windowManager.CreateWindow(model, false); ((IChildDelegate)model.Parent).CloseItem(new object()); } @@ -244,7 +232,7 @@ namespace StyletUnitTests { var model = new Mock(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(window); object parent = null; model.SetupSet(x => x.Parent = It.IsAny()).Callback((object x) => parent = x); this.windowManager.CreateWindow(model.Object, false); @@ -258,7 +246,7 @@ namespace StyletUnitTests { var model = new Mock(); var window = new MyWindow(); - this.viewManager.Setup(x => x.CreateAndSetupViewForModel(model.Object)).Returns(window); + this.viewManager.Setup(x => x.CreateAndBindViewForModel(model.Object)).Returns(window); object parent = null; model.SetupSet(x => x.Parent = It.IsAny()).Callback((object x) => parent = x); this.windowManager.CreateWindow(model.Object, true);