有人可以快速总结一下ViewModelLocator是什么,它是如何工作的,以及与DataTemplates相比使用它的优缺点是什么?
我曾尝试在Google上查找信息,但似乎有很多不同的实现,并且没有严格的列表,关于它是什么以及使用它的优缺点。
答案 0 :(得分:186)
在MVVM中,通常的做法是让Views通过从dependency injection(DI)容器中解析它们来查找它们的ViewModel。当要求容器提供(解析)View类的实例时,会自动发生这种情况。容器通过调用View的构造函数将ViewModel注入到View中,该构造函数接受ViewModel参数;这种方案称为控制反转(IoC)。
这里的主要好处是可以在运行时配置容器,并提供有关如何解析我们从中请求的类型的说明。这允许通过指示它解析我们的应用程序实际运行时使用的类型(视图和视图模型)来提高可测试性,但在运行应用程序的单元测试时以不同方式指示它。在后一种情况下,应用程序甚至没有UI(它没有运行;只是测试),因此容器将解析mocks来代替应用程序运行时使用的“普通”类型。
到目前为止,我们已经看到DI方法通过在应用程序组件的创建上添加抽象层,使应用程序易于测试。这种方法存在一个问题:它与视觉设计师不兼容,如Microsoft Expression Blend。
问题在于,在正常的应用程序运行和单元测试运行中,有人必须设置容器,并提供有关要解决的类型的说明;此外,有人必须要求容器来解析视图,以便可以将ViewModel注入其中。
但是,在设计时,没有我们运行的代码。设计者尝试使用反射来创建视图的实例,这意味着:
DataContext
将是null
所以我们将在设计器中获得一个“空”视图 - 这不是很有用ViewModelLocator是一个额外的抽象,使用如下:
当然这意味着View必须有一个无参数构造函数(否则设计器将无法实例化它)。
ViewModelLocator是一个成语,它可以让您在MVVM应用程序中保留DI的好处,同时还允许您的代码与视觉设计师一起玩。这有时被称为应用程序的“可混合性”(指Expression Blend)。
在消化了上述内容后,请参阅一个实际示例here。
最后,使用数据模板不是使用ViewModelLocator的替代方法,而是为UI的部分使用显式View / ViewModel对的替代方法。通常您可能会发现无需为ViewModel定义View,因为您可以使用数据模板。
答案 1 :(得分:8)
我有一个视图模型定位器类。每个属性都将成为我将在视图中分配的视图模型的实例。我可以使用DesignerProperties.GetIsInDesignMode
检查代码是否在设计模式下运行。这允许我在设计时使用模拟模型,在运行应用程序时使用真实对象。
public class ViewModelLocator
{
private DependencyObject dummy = new DependencyObject();
public IMainViewModel MainViewModel
{
get
{
if (IsInDesignMode())
{
return new MockMainViewModel();
}
return MyIoC.Container.GetExportedValue<IMainViewModel>();
}
}
// returns true if editing .xaml file in VS for example
private bool IsInDesignMode()
{
return DesignerProperties.GetIsInDesignMode(dummy);
}
}
要使用它,我可以将我的定位器添加到App.xaml
资源:
xmlns:core="clr-namespace:MyViewModelLocatorNamespace"
<Application.Resources>
<core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>
然后将您的视图(例如:MainView.xaml)连接到您的viewmodel:
<Window ...
DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">
答案 2 :(得分:2)
我不明白为什么这个问题的其他答案都围绕着设计师。
View Model Locator的目的是允许View实例化它(是的,View Model Locator = View First):
a
而不仅仅是这个:
public void MyWindowViewModel(IService someService)
{
}
宣布:
public void MyWindowViewModel()
{
}
其中DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"
是类,它引用了IoC以及它如何解决它所公开的ViewModelLocator
属性。
它与为视图提供模拟视图模型无关。如果你想要,那就做吧
MainWindowModel
View Model Locator是一些(任何)Inversion of Control容器的包装器,例如Unity。
参考: