什么是 ViewModelLocator 以及它与 DataTemplate 相比有何优缺点?
有人可以给我快速总结一下 ViewModelLocator 是什么、它是如何工作的以及与 DataTemplates 相比使用它的优点/缺点是什么?
我尝试在谷歌上查找信息,但似乎有许多不同的实现,并且没有直接列出它是什么以及使用它的优点/缺点。
Can someone give me a quick summary of what a ViewModelLocator is, how it works, and what the pros/cons are for using it compared to DataTemplates?
I have tried finding info on Google but there seems to be many different implementations of it and no striaght list as to what it is and the pros/cons of using it.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
在 MVVM 中,通常的做法
是让视图通过依赖注入解析它们来找到它们的 ViewModel。 (DI) 容器。当要求容器提供(解析)View 类的实例时,这种情况会自动发生。容器通过调用接受 ViewModel 参数的 View 构造函数,将 ViewModel 注入到 View 中;这种方案称为控制反转 (IoC)。
DI 的优点
这里的主要优点是可以在运行时配置容器,并提供有关如何解析我们请求的类型的说明。这可以通过指示它解析我们在应用程序实际运行时使用的类型(视图和 ViewModel)来实现更高的可测试性,但在运行应用程序的单元测试时以不同的方式指示它。在后一种情况下,应用程序甚至没有 UI(它没有运行;只是测试),因此容器将解析 模拟 代替应用程序运行时使用的“正常”类型。
源自 DI 的问题
到目前为止,我们已经看到 DI 方法通过在应用程序组件的创建上添加抽象层,可以轻松地实现应用程序的可测试性。这种方法有一个问题:它不能很好地与 Microsoft Expression Blend 等可视化设计器配合使用。
问题是,在正常的应用程序运行和单元测试运行中,必须有人设置容器,并提供有关要解析的类型的说明;此外,必须有人请求容器解析视图,以便将 ViewModel 注入其中。
然而,在设计时,我们的代码没有运行。设计器尝试使用反射来创建 View 的实例,这意味着:
输入 ViewModelLocator
ViewModelLocator 是一个额外的抽象,使用方式如下:
当然,这意味着 View 必须首先有一个无参数构造函数(否则设计者将无法实例化它)。
总结
ViewModelLocator 是一种习惯用法,它可以让您在 MVVM 应用程序中保留 DI 的优势,同时还可以让您的代码与可视化设计器很好地配合。这有时称为应用程序的“可混合性”(指 Expression Blend)。
消化完上面的内容后,看一个实际的例子此处。
最后,使用数据模板并不是使用 ViewModelLocator 的替代方法,而是对 UI 部分使用显式 View/ViewModel 对的替代方法。通常您可能会发现不需要为 ViewModel 定义视图,因为您可以使用数据模板。
Intro
In MVVM the usual practice is to have the Views find their ViewModels by resolving them from a dependency injection (DI) container. This happens automatically when the container is asked to provide (resolve) an instance of the View class. The container injects the ViewModel into the View by calling a constructor of the View which accepts a ViewModel parameter; this scheme is called inversion of control (IoC).
Benefits of DI
The main benefit here is that the container can be configured at run time with instructions on how to resolve the types that we request from it. This allows for greater testability by instructing it to resolve the types (Views and ViewModels) we use when our application actually runs, but instructing it differently when running the unit tests for the application. In the latter case the application will not even have a UI (it's not running; just the tests are) so the container will resolve mocks in place of the "normal" types used when the application runs.
Problems stemming from DI
So far we have seen that the DI approach allows easy testability for the application by adding an abstraction layer over the creation of application components. There is one problem with this approach: it doesn't play well with visual designers such as Microsoft Expression Blend.
The problem is that in both normal application runs and unit test runs, someone has to set up the container with instructions on what types to resolve; additionally, someone has to ask the container to resolve the Views so that the ViewModels can be injected into them.
However, in design time there is no code of ours running. The designer attempts to use reflection to create instances of our Views, which means that:
DataContext
will benull
so we 'll get an "empty" view in the designer -- which is not very usefulEnter ViewModelLocator
The ViewModelLocator is an additional abstraction used like this:
Of course this means that the View must have a parameterless constructor to begin with (otherwise the designer won't be able to instantiate it).
Summary
ViewModelLocator is an idiom that lets you keep the benefits of DI in your MVVM application while also allowing your code to play well with visual designers. This is sometimes called the "blendability" of your application (referring to Expression Blend).
After digesting the above, see a practical example here.
Finally, using data templates is not an alternative to using ViewModelLocator, but an alternative to using explicit View/ViewModel pairs for parts of your UI. Often you may find that there's no need to define a View for a ViewModel because you can use a data template instead.
@Jon 的回答的示例实现
我有一个视图模型定位器类。每个属性都将是我将在视图上分配的视图模型的一个实例。我可以使用
DesignerProperties.GetIsInDesignMode
检查代码是否在设计模式下运行。这使我可以在设计时使用模拟模型,并在运行应用程序时使用真实对象。要使用它,我可以将定位器添加到 App.xaml 资源中:
然后将视图(例如:MainView.xaml)连接到视图模型:
An example implementation of @Jon's answer
I have a view model locator class. Each property is going to be an instance of the view model that I'm going to allocate on my view. I can check if the code is running in design mode or not using
DesignerProperties.GetIsInDesignMode
. This allows me to use a mock model during designing time and the real object when I'm running the application.And to use it I can add my locator to
App.xaml
resources:And then to wire up your view (ex: MainView.xaml) to your viewmodel:
我不明白为什么这个问题的其他答案都围绕着设计师。
视图模型定位器的目的是允许您的视图实例化它(是的,视图模型定位器 = View First):
而不仅仅是这样:
通过声明:
其中
ViewModelLocator
是类,它引用一个IoC,这就是它解决其公开的MainWindowModel
属性的方式。它与向您的视图提供模拟视图模型无关。如果您想要这样做,只需执行
“视图模型定位器”是某些(任何)控制反转容器(例如 Unity)的包装器。
请参阅:
I don't understand why the other answers of this question wrap around the Designer.
The purpose of the View Model Locator is to allow your View to instantiate this (yes, View Model Locator = View First):
instead of just this:
by declaring this:
Where
ViewModelLocator
is class, which references a IoC and that's how it solves theMainWindowModel
property it exposes.It has nothing to do with providing Mock view models to your view. If you want that, just do
The View Model Locator is a wrapper around some (any) Inversion of Control container, such as Unity for example.
Refer to: