Wpf 什么是ViewModelLocator?与DataTemplates相比,它的优缺点是什么?

Wpf 什么是ViewModelLocator?与DataTemplates相比,它的优缺点是什么?,wpf,mvvm,datatemplate,mvvm-light,viewmodellocator,Wpf,Mvvm,Datatemplate,Mvvm Light,Viewmodellocator,有人能给我一个关于ViewModelLocator是什么、它是如何工作的以及与DataTemplates相比使用它的优缺点的快速总结吗 我曾尝试在谷歌上查找信息,但似乎有许多不同的实现方式,对于它是什么以及使用它的优缺点,没有一个严格的列表。Intro 在MVVM中,通常的做法是让视图通过从(DI)容器解析它们来找到它们的视图模型。当要求容器提供(解析)视图类的实例时,会自动发生这种情况。容器通过调用接受ViewModel参数的视图构造函数将ViewModel注入视图;这种方案称为控制反转(Io

有人能给我一个关于ViewModelLocator是什么、它是如何工作的以及与DataTemplates相比使用它的优缺点的快速总结吗

我曾尝试在谷歌上查找信息,但似乎有许多不同的实现方式,对于它是什么以及使用它的优缺点,没有一个严格的列表。

Intro 在MVVM中,通常的做法是让视图通过从(DI)容器解析它们来找到它们的视图模型。当要求容器提供(解析)视图类的实例时,会自动发生这种情况。容器通过调用接受ViewModel参数的视图构造函数将ViewModel注入视图;这种方案称为控制反转(IoC)

直接投资的好处 这里的主要好处是,可以在运行时配置容器,并提供有关如何解析我们向其请求的类型的说明。这允许通过指示它解析我们在应用程序实际运行时使用的类型(视图和视图模型),但在运行应用程序的单元测试时以不同的方式指示它,从而实现更高的可测试性。在后一种情况下,应用程序甚至没有UI(它没有运行;只有测试在运行),因此容器将解析应用程序运行时使用的“普通”类型

源于DI的问题 到目前为止,我们已经看到,DI方法通过在应用程序组件的创建上添加一个抽象层,使应用程序易于测试。这种方法有一个问题:它不能很好地与视觉设计师合作,例如Microsoft Expression Blend

问题是,在正常的应用程序运行和单元测试运行中,必须有人设置容器,并说明要解决的类型;此外,必须有人要求容器解析视图,以便将ViewModels注入其中

然而,在设计阶段没有我们运行的代码。设计师尝试使用反射创建视图实例,这意味着:

  • 如果视图构造函数需要一个ViewModel实例,那么设计器将根本无法实例化视图——它将以某种可控的方式出错
  • 如果视图有一个无参数构造函数,那么视图将被实例化,但是它的
    DataContext
    将是
    null
    ,因此我们将在设计器中得到一个“空”视图——这不是很有用
输入ViewModelLocator ViewModelLocator是这样使用的附加抽象:

  • 视图本身实例化ViewModelLocator作为其数据的一部分,并将其DataContext绑定到定位器的ViewModel属性
  • 定位器以某种方式检测我们是否处于设计模式
  • 如果未处于设计模式,定位器将返回它从DI容器解析的ViewModel,如上所述
  • 如果在设计模式下,定位器使用自己的逻辑返回一个固定的“虚拟”ViewModel(请记住:设计时没有容器!);此ViewModel通常预先填充了虚拟数据
当然,这意味着视图必须首先有一个无参数构造函数(否则设计器将无法实例化它)

总结 ViewModelLocator是一种习惯用法,它允许您在MVVM应用程序中保留DI的优点,同时也允许您的代码与可视化设计器配合良好。这有时被称为应用程序的“可混合性”(指表达式混合)

消化以上内容后,请参见一个实际示例


最后,使用数据模板不是使用ViewModelLocator的替代方法,而是对UI的某些部分使用显式视图/视图模型对的替代方法。通常,您可能会发现不需要为ViewModel定义视图,因为您可以使用数据模板

我有一个视图模型定位器类。每个属性都将是我将在视图上分配的视图模型的实例。我可以检查代码是否在设计模式下运行,或者是否未使用
DesignerProperties.GetIsInDesignMode
。这允许我在设计时使用模拟模型,在运行应用程序时使用真实对象

公共类ViewModelLocator
{
私有DependencyObject伪=新DependencyObject();
公共IMainViewModel主视图模型
{
得到
{
如果(IsInDesignMode())
{
返回新的MockMainViewModel();
}
返回MyIoC.Container.GetExportedValue();
}
}
//例如,如果在VS中编辑.xaml文件,则返回true
私有布尔IsInDesignMode()
{
返回DesignerProperties.GetIsInDesignMode(虚拟);
}
}
要使用它,我可以将我的定位器添加到
App.xaml
资源:

xmlns:core="clr-namespace:MyViewModelLocatorNamespace"

<Application.Resources>
    <core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>
xmlns:core=“clr命名空间:MyViewModelLocatorNamespace”
然后将视图(例如:MainView.xaml)连接到viewmodel:


我不明白为什么这个问题的其他答案围绕着设计师

视图模型定位器的用途是允许您的视图对此进行实例化(是的,视图模型定位器=视图优先):

public void MyWindowViewModel(iSeries服务)
{
}
而不仅仅是这样:

public void MyWindowViewModel()
{
}
宣布:

DataContext=“{Binding MainWindowModel,Source={StaticResource ViewModelLocator}”
其中,
ViewModelLocator
是类,它引用了一个IoC,这就是它如何解决它公开的
MainWindowModel
属性的方法

它与为视图提供模拟视图模型无关。如果你想要的话,就这么做吧

d:DataContext=“{d:DesignInstance MockViewModels:MockMainWindowModel,IsDesignTimeCreatable=True}”