在本章中,我们将介绍如何连接ViewModel.这是我们讨论View第一个结构的最后一章的延续.现在,第一种结构的下一种形式是元模式,它被称为 ViewModelLocator .它是一个伪模式,并且位于MVVM模式之上.
在MVVM中,每个View都需要连接起来ViewModelLocator是一种集中代码和解耦视图的简单方法.
这意味着它不必明确了解ViewModel类型以及如何构建它.
有许多不同的方法使用ViewModelLocator,但在这里我们使用与PRISM框架中最相似的那个.
ViewModelLocator提供标准,一致的,声明性和松散耦合的方式来查看第一个构造,自动化ViewModel连接到View的过程.下图表示ViewModelLocator的高级过程.
第1步 : 找出正在构建的View类型.
第2步 : 确定特定视图类型的ViewModel.
第3步 : 构建ViewModel.
第4步 : 将Views DataContext设置为ViewModel.
要理解基本概念,让我们通过继续上一章中的相同示例来查看ViewModelLocator的简单示例.如果查看StudentView.xaml文件,您将看到我们已静态连接ViewModel.
现在,如下面的程序所示,注释这些XAML代码也会删除代码代码隐藏.
现在让我们创建一个新的文件夹VML并添加一个新的公共类ViewModelLocator,它将包含一个附加属性(依赖属性)AutoHookedUpViewModel,如下面的代码所示.
public static bool GetAutoHookedUpViewModel(DependencyObject obj) { return (bool)obj.GetValue(AutoHookedUpViewModelProperty); }public static void SetAutoHookedUpViewModel(DependencyObject obj, bool value) { obj.SetValue(AutoHookedUpViewModelProperty, value); }// Using a DependencyProperty as the backing store for AutoHookedUpViewModel. //This enables animation, styling, binding, etc... public static readonly DependencyProperty AutoHookedUpViewModelProperty = DependencyProperty.RegisterAttached("AutoHookedUpViewModel", typeof(bool), typeof(ViewModelLocator), new PropertyMetadata(false, AutoHookedUpViewModelChanged));
现在你可以看到一个基本的附件属性定义.要向属性添加行为,我们需要为此属性添加更改的事件处理程序,其中包含连接ViewModel for View的自动过程.执行此操作的代码如下 :
private static void AutoHookedUpViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (DesignerProperties.GetIsInDesignMode(d)) return; var viewType = d.GetType(); string str = viewType.FullName; str = str.Replace(".Views.", ".ViewModel."); var viewTypeName = str; var viewModelTypeName = viewTypeName + "Model"; var viewModelType = Type.GetType(viewModelTypeName); var viewModel = Activator.CreateInstance(viewModelType); ((FrameworkElement)d).DataContext = viewModel; }
以下是ViewModelLocator类的完整实现.
using System; using System.ComponentModel; using System.Windows;namespace MVVMDemo.VML { public static class ViewModelLocator { public static bool GetAutoHookedUpViewModel(DependencyObject obj) { return (bool)obj.GetValue(AutoHookedUpViewModelProperty); } public static void SetAutoHookedUpViewModel(DependencyObject obj, bool value) { obj.SetValue(AutoHookedUpViewModelProperty, value); } // Using a DependencyProperty as the backing store for AutoHookedUpViewModel. //This enables animation, styling, binding, etc... public static readonly DependencyProperty AutoHookedUpViewModelProperty = DependencyProperty.RegisterAttached("AutoHookedUpViewModel", typeof(bool), typeof(ViewModelLocator), new PropertyMetadata(false, AutoHookedUpViewModelChanged)); private static void AutoHookedUpViewModelChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) { if (DesignerProperties.GetIsInDesignMode(d)) return; var viewType = d.GetType(); string str = viewType.FullName; str = str.Replace(".Views.", ".ViewModel."); var viewTypeName = str; var viewModelTypeName = viewTypeName + "Model"; var viewModelType = Type.GetType(viewModelTypeName); var viewModel = Activator.CreateInstance(viewModelType); ((FrameworkElement)d).DataContext = viewModel; } } }
首先要做的是添加命名空间,以便我们可以访问ViewModelLocator输入我们项目的根目录.然后在作为视图类型的route元素上,添加AutoHookedUpViewModel属性并将其设置为true.
xmlns:vml = "clr-namespace:MVVMDemo.VML"vml:ViewModelLocator.AutoHookedUpViewModel = "True"
以下是StudentView.xaml文件的完整实现.
编译并执行上述代码时,您将看到ViewModelLocator正在连接该特定View的ViewModel.
要注意的一个关键是视图不再耦合一种方式,了解ViewModel的类型或构造方式.这一切都被移到了ViewModelLocator内部的中心位置.