Get rid of the static ViewLocator and ViewModelBinder, and replace with the singleton ViewManager

This commit is contained in:
Antony Male 2014-02-23 20:02:18 +00:00
parent 1607dc9ad3
commit 40c9d4ed88
7 changed files with 93 additions and 95 deletions

View File

@ -26,6 +26,7 @@ namespace Stylet
{
builder.Autobind(AssemblySource.Assemblies);
builder.Bind<IWindowManager>().To<WindowManager>().InSingletonScope();
builder.Bind<IViewManager>().To<ViewManager>().InSingletonScope();
}
protected override object GetInstance(Type service, string key = null)

View File

@ -71,8 +71,7 @@
<Compile Include="StyletIoC\StyletIoCContainer.cs" />
<Compile Include="StyletIoC\UnboundGeneric.cs" />
<Compile Include="View.cs" />
<Compile Include="ViewLocator.cs" />
<Compile Include="ViewModelBinder.cs" />
<Compile Include="ViewManager.cs" />
<Compile Include="WindowManager.cs" />
</ItemGroup>
<ItemGroup>

View File

@ -41,37 +41,10 @@ namespace Stylet
// Using a DependencyProperty as the backing store for Model. This enables animation, styling, binding, etc...
public static readonly DependencyProperty ModelProperty =
DependencyProperty.RegisterAttached("Model", typeof(object), typeof(View), new PropertyMetadata(null, OnModelChanged));
DependencyProperty.RegisterAttached("Model", typeof(object), typeof(View), new PropertyMetadata(null, (d, e) => IoC.Get<IViewManager>().OnModelChanged(d, e) ));
private static void OnModelChanged(DependencyObject targetLocation, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue == e.NewValue)
return;
if (e.NewValue != null)
{
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);
}
else
{
SetContentProperty(targetLocation, null);
}
}
private static void SetContentProperty(DependencyObject targetLocation, UIElement view)
public static void SetContentProperty(DependencyObject targetLocation, UIElement view)
{
var type = targetLocation.GetType();
var contentProperty = Attribute.GetCustomAttributes(type, true).OfType<ContentPropertyAttribute>().FirstOrDefault() ?? DefaultContentProperty;

View File

@ -1,37 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
namespace Stylet
{
public static class ViewLocator
{
public static UIElement LocateForModel(object model)
{
var modelName = model.GetType().FullName;
var viewName = Regex.Replace(modelName, @"ViewModel", "View");
// TODO: This might need some more thinking
var viewType = AssemblySource.Assemblies.SelectMany(x => x.GetExportedTypes()).FirstOrDefault(x => x.FullName == viewName);
if (viewType == null)
throw new Exception(String.Format("Unable to find a View with type {0}", viewName));
if (viewType.IsInterface || viewType.IsAbstract || !typeof(UIElement).IsAssignableFrom(viewType))
throw new Exception(String.Format("Found type for view : {0}, but it wasn't a class derived from UIElement", viewType.Name));
var view = (UIElement)IoC.GetInstance(viewType, null);
// If it doesn't have a code-behind, this won't be called
var initializer = viewType.GetMethod("InitializeComponent", BindingFlags.Public | BindingFlags.Instance);
if (initializer != null)
initializer.Invoke(view, null);
return (UIElement)view;
}
}
}

85
Stylet/ViewManager.cs Normal file
View File

@ -0,0 +1,85 @@
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using System.Windows;
namespace Stylet
{
public interface IViewManager
{
void OnModelChanged(DependencyObject targetLocation, DependencyPropertyChangedEventArgs e);
UIElement LocateViewForModel(object model);
void BindViewToModel(UIElement view, object viewModel);
}
public class ViewManager : IViewManager
{
public virtual void OnModelChanged(DependencyObject targetLocation, DependencyPropertyChangedEventArgs e)
{
if (e.OldValue == e.NewValue)
return;
if (e.NewValue != null)
{
UIElement view;
var viewModelAsViewAware = e.NewValue as IViewAware;
if (viewModelAsViewAware != null && viewModelAsViewAware.View != null)
{
view = viewModelAsViewAware.View;
}
else
{
view = this.LocateViewForModel(e.NewValue);
this.BindViewToModel(view, e.NewValue);
}
View.SetContentProperty(targetLocation, view);
}
else
{
View.SetContentProperty(targetLocation, null);
}
}
public virtual UIElement LocateViewForModel(object model)
{
var modelName = model.GetType().FullName;
var viewName = Regex.Replace(modelName, @"ViewModel", "View");
// TODO: This might need some more thinking
var viewType = AssemblySource.Assemblies.SelectMany(x => x.GetExportedTypes()).FirstOrDefault(x => x.FullName == viewName);
if (viewType == null)
throw new Exception(String.Format("Unable to find a View with type {0}", viewName));
if (viewType.IsInterface || viewType.IsAbstract || !typeof(UIElement).IsAssignableFrom(viewType))
throw new Exception(String.Format("Found type for view : {0}, but it wasn't a class derived from UIElement", viewType.Name));
var view = (UIElement)IoC.GetInstance(viewType, null);
// If it doesn't have a code-behind, this won't be called
var initializer = viewType.GetMethod("InitializeComponent", BindingFlags.Public | BindingFlags.Instance);
if (initializer != null)
initializer.Invoke(view, null);
return view;
}
public virtual void BindViewToModel(UIElement view, object viewModel)
{
View.SetTarget(view, viewModel);
var viewAsFrameworkElement = view as FrameworkElement;
if (viewAsFrameworkElement != null)
viewAsFrameworkElement.DataContext = viewModel;
var viewModelAsViewAware = viewModel as IViewAware;
if (viewModelAsViewAware != null)
viewModelAsViewAware.AttachView(view);
}
}
}

View File

@ -1,25 +0,0 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
namespace Stylet
{
public static class ViewModelBinder
{
public static void Bind(UIElement view, object viewModel)
{
View.SetTarget(view, viewModel);
var viewAsFrameworkElement = view as FrameworkElement;
if (viewAsFrameworkElement != null)
viewAsFrameworkElement.DataContext = viewModel;
var viewModelAsViewAware = viewModel as IViewAware;
if (viewModelAsViewAware != null)
viewModelAsViewAware.AttachView(view);
}
}
}

View File

@ -30,11 +30,13 @@ namespace Stylet
private Window CreateWindow(object viewModel, bool isDialog)
{
var view = ViewLocator.LocateForModel(viewModel) as Window;
var viewManager = IoC.Get<IViewManager>();
var view = viewManager.LocateViewForModel(viewModel) as Window;
if (view == null)
throw new Exception(String.Format("Tried to show {0} as a window, but it isn't a Window", view.GetType().Name));
ViewModelBinder.Bind(view, viewModel);
viewManager.BindViewToModel(view, viewModel);
var haveDisplayName = viewModel as IHaveDisplayName;
if (haveDisplayName != null)