From 9da84610047dc15477024d5ad6ce8e26f5993695 Mon Sep 17 00:00:00 2001 From: Antony Male Date: Sat, 22 Feb 2014 21:24:36 +0000 Subject: [PATCH] Fix conductors, view binding, and add the WindowConductor --- Samples/Stylet.Samples.sln | 6 +++ Stylet/ConductorBaseWithActiveItem.cs | 6 +-- Stylet/IScreen.cs | 4 +- Stylet/Screen.cs | 14 ++--- Stylet/View.cs | 13 ++++- Stylet/ViewModelBinder.cs | 2 +- Stylet/WindowManager.cs | 73 +++++++++++++++++++++++++++ 7 files changed, 103 insertions(+), 15 deletions(-) diff --git a/Samples/Stylet.Samples.sln b/Samples/Stylet.Samples.sln index a9084b4..2f39dac 100644 --- a/Samples/Stylet.Samples.sln +++ b/Samples/Stylet.Samples.sln @@ -7,6 +7,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stylet", "..\Stylet\Stylet. EndProject Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stylet.Samples.Hello", "Stylet.Samples.Hello\Stylet.Samples.Hello.csproj", "{6C7FBB21-52AC-4333-A42A-9F5E9D048621}" EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Stylet.Samples.TabNavigation", "Stylet.Samples.TabNavigation\Stylet.Samples.TabNavigation.csproj", "{9A4E2DAD-AE68-4A82-8FA8-407DB74D6FBE}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU @@ -21,6 +23,10 @@ Global {6C7FBB21-52AC-4333-A42A-9F5E9D048621}.Debug|Any CPU.Build.0 = Debug|Any CPU {6C7FBB21-52AC-4333-A42A-9F5E9D048621}.Release|Any CPU.ActiveCfg = Release|Any CPU {6C7FBB21-52AC-4333-A42A-9F5E9D048621}.Release|Any CPU.Build.0 = Release|Any CPU + {9A4E2DAD-AE68-4A82-8FA8-407DB74D6FBE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {9A4E2DAD-AE68-4A82-8FA8-407DB74D6FBE}.Debug|Any CPU.Build.0 = Debug|Any CPU + {9A4E2DAD-AE68-4A82-8FA8-407DB74D6FBE}.Release|Any CPU.ActiveCfg = Release|Any CPU + {9A4E2DAD-AE68-4A82-8FA8-407DB74D6FBE}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/Stylet/ConductorBaseWithActiveItem.cs b/Stylet/ConductorBaseWithActiveItem.cs index 3d33d7b..e41972d 100644 --- a/Stylet/ConductorBaseWithActiveItem.cs +++ b/Stylet/ConductorBaseWithActiveItem.cs @@ -27,12 +27,10 @@ namespace Stylet newItem = this.EnsureItem(newItem); if (this.IsActive) - { ScreenExtensions.TryActivate(newItem); - this._activeItem = newItem; - this.NotifyOfPropertyChange(() => this.ActiveItem); - } + this._activeItem = newItem; + this.NotifyOfPropertyChange(() => this.ActiveItem); } protected override void OnActivate() diff --git a/Stylet/IScreen.cs b/Stylet/IScreen.cs index ea657d4..92efbce 100644 --- a/Stylet/IScreen.cs +++ b/Stylet/IScreen.cs @@ -3,12 +3,14 @@ using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; +using System.Windows; namespace Stylet { public interface IViewAware { - void AttachView(object view); + UIElement View { get; } + void AttachView(UIElement view); } public interface IActivate diff --git a/Stylet/Screen.cs b/Stylet/Screen.cs index 957acf4..b0083b0 100644 --- a/Stylet/Screen.cs +++ b/Stylet/Screen.cs @@ -13,7 +13,7 @@ namespace Stylet public virtual void TryClose(bool? dialogResult = null) { // TODO: Check for parent conductor - var viewWindow = this.view as Window; + var viewWindow = this.View as Window; if (viewWindow != null) { if (dialogResult != null) @@ -22,7 +22,7 @@ namespace Stylet return; } - var viewPopover = this.view as Popup; + var viewPopover = this.View as Popup; if (viewPopover != null) { viewPopover.IsOpen = false; @@ -98,7 +98,7 @@ namespace Stylet handler(this, new DeactivationEventArgs() { WasClosed = close }); if (close) - this.view = null; + this.View = null; } protected virtual void OnDeactivate(bool close) { } @@ -107,14 +107,14 @@ namespace Stylet #region IViewAware - private object view; + public UIElement View { get; private set; } - void IViewAware.AttachView(object view) + void IViewAware.AttachView(UIElement view) { - if (this.view != null) + if (this.View != null) throw new Exception(String.Format("Tried to attach View {0} to ViewModel {1}, but it already has a view attached", view.GetType().Name, this.GetType().Name)); - this.view = view; + this.View = view; var viewAsFrameworkElement = view as FrameworkElement; if (viewAsFrameworkElement != null) diff --git a/Stylet/View.cs b/Stylet/View.cs index 4691938..4528141 100644 --- a/Stylet/View.cs +++ b/Stylet/View.cs @@ -51,8 +51,17 @@ namespace Stylet if (e.NewValue != null) { - var view = ViewLocator.LocateForModel(e.NewValue); - ViewModelBinder.Bind(view, e.NewValue); + UIElement view; + var viewModelAsViewAware = e.NewValue as IViewAware; + if (viewModelAsViewAware != null && viewModelAsViewAware.View != null) + { + view = viewModelAsViewAware.View; + } + else + { + view = ViewLocator.LocateForModel(e.NewValue); + ViewModelBinder.Bind(view, e.NewValue); + } SetContentProperty(targetLocation, view); } diff --git a/Stylet/ViewModelBinder.cs b/Stylet/ViewModelBinder.cs index 4be6172..d004af5 100644 --- a/Stylet/ViewModelBinder.cs +++ b/Stylet/ViewModelBinder.cs @@ -9,7 +9,7 @@ namespace Stylet { public static class ViewModelBinder { - public static void Bind(DependencyObject view, object viewModel) + public static void Bind(UIElement view, object viewModel) { View.SetTarget(view, viewModel); diff --git a/Stylet/WindowManager.cs b/Stylet/WindowManager.cs index b37e211..4d406e8 100644 --- a/Stylet/WindowManager.cs +++ b/Stylet/WindowManager.cs @@ -1,5 +1,6 @@ using System; using System.Collections.Generic; +using System.ComponentModel; using System.Linq; using System.Text; using System.Threading.Tasks; @@ -49,6 +50,8 @@ namespace Stylet view.Owner = owner; } + new WindowConductor(view, viewModel); + return view; } @@ -60,5 +63,75 @@ namespace Stylet var active = Application.Current.Windows.OfType().Where(x => x.IsActive).FirstOrDefault() ?? Application.Current.MainWindow; return active == window ? null : active; } + + class WindowConductor + { + private readonly Window window; + private readonly object viewModel; + + public WindowConductor(Window window, object viewModel) + { + this.window = window; + this.viewModel = viewModel; + + var viewModelAsActivate = viewModel as IActivate; + if (viewModelAsActivate != null) + viewModelAsActivate.Activate(); + + var viewModelAsDeactivate = viewModel as IDeactivate; + if (viewModelAsDeactivate != null) + { + window.Closed += this.Closed; + viewModelAsDeactivate.Deactivated += this.Deactivated; + } + + if (viewModel is IGuardClose) + window.Closing += this.Closing; + } + + private void Closed(object sender, EventArgs e) + { + var viewModelAsDeactivate = (IDeactivate)this.viewModel; + + this.window.Closed -= this.Closed; + this.window.Closing -= this.Closing; // Not sure this is required + viewModelAsDeactivate.Deactivated -= this.Deactivated; + + viewModelAsDeactivate.Deactivate(true); + } + + private void Deactivated(object sender, DeactivationEventArgs e) + { + if (!e.WasClosed) + return; + + this.window.Closed -= this.Closed; + this.window.Closing -= this.Closing; + ((IDeactivate)this.window).Deactivated -= this.Deactivated; + this.window.Close(); + } + + private async void Closing(object sender, CancelEventArgs e) + { + if (e.Cancel) + return; + + // See if the task completed synchronously + var task = ((IGuardClose)this.viewModel).CanCloseAsync(); + if (task.IsCompleted) + { + e.Cancel = !task.Result; + } + else + { + e.Cancel = true; + if (await task) + { + this.window.Closing -= this.Closing; + this.window.Close(); + } + } + } + } } }