wpf 什么是 ViewModelLocator,与 DataTemplates 相比,它的优缺点是什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/5462040/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
What is a ViewModelLocator and what are its pros/cons compared to DataTemplates?
提问by Rachel
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?
有人可以快速总结一下 ViewModelLocator 是什么,它是如何工作的,以及与 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.
我曾尝试在 Google 上查找信息,但似乎有许多不同的实现方式,并且没有明确列出它是什么以及使用它的利弊。
回答by Jon
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 injectsthe ViewModel into the View by calling a constructor of the View which accepts a ViewModel parameter; this scheme is called inversion of control(IoC).
在 MVVM 中,通常的做法是让视图通过从依赖注入(DI) 容器解析它们来找到它们的 ViewModel 。当要求容器提供(解析)View 类的实例时,这会自动发生。容器通过调用接受 ViewModel 参数的 View 的构造函数将ViewModel 注入到 View 中;这种方案称为控制反转(IoC)。
Benefits of DI
直接投资的好处
The main benefit here is that the container can be configured at run timewith 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 mocksin place of the "normal" types used when the application runs.
这里的主要好处是可以在运行时配置容器,并提供有关如何解析我们从它请求的类型的说明。这允许通过指示它解析我们在应用程序实际运行时使用的类型(视图和视图模型)来实现更高的可测试性,但在运行应用程序的单元测试时以不同的方式指示它。在后一种情况下,应用程序甚至不会有 UI(它没有运行;只有测试),因此容器将解析模拟来代替应用程序运行时使用的“正常”类型。
Problems stemming from DI
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 designerssuch as Microsoft Expression Blend.
到目前为止,我们已经看到,DI 方法通过在应用程序组件的创建上添加一个抽象层,可以轻松地对应用程序进行测试。这种方法存在一个问题:它不适用于 Microsoft Expression Blend 等视觉设计器。
The problem is that in both normal application runs and unit test runs, someone has to set upthe container with instructions on what types to resolve; additionally, someone has to askthe 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:
但是,在设计时没有我们的代码运行. 设计者尝试使用反射来创建我们的视图的实例,这意味着:
- If the View constructor requires a ViewModel instance the designer won't be able to instantiate the View at all -- it will error out in some controlled manner
- If the View has a parameterless constructor the View will be instantiated, but its
DataContext
will benull
so we 'll get an "empty" view in the designer -- which is not very useful
- 如果 View 构造函数需要一个 ViewModel 实例,设计者将根本无法实例化 View——它会以某种受控方式出错
- 如果 View 有一个无参数的构造函数,则 View 将被实例化,但它
DataContext
会是null
这样,我们将在设计器中得到一个“空”视图——这不是很有用
Enter ViewModelLocator
输入 ViewModelLocator
The ViewModelLocator is an additional abstraction used like this:
ViewModelLocator 是一个额外的抽象,像这样使用:
- The View itself instantiates a ViewModelLocator as part of its resourcesand databinds its DataContext to the ViewModel property of the locator
- The locator somehow detects if we are in design mode
- If not in design mode, the locator returns a ViewModel that it resolves from the DI container, as explained above
- If in design mode, the locator returns a fixed "dummy" ViewModel using its own logic (remember: there is no container in design time!); this ViewModel typically comes prepopulated with dummy data
- View 本身实例化一个 ViewModelLocator 作为其资源的一部分,并将其 DataContext 数据绑定到定位器的 ViewModel 属性
- 定位器以某种方式检测我们是否处于设计模式
- 如果不在设计模式下,定位器将返回一个它从 DI 容器解析的 ViewModel,如上所述
- 如果在设计模式下,定位器使用自己的逻辑返回一个固定的“虚拟”ViewModel(记住:设计时没有容器!);这个 ViewModel 通常预先填充了虚拟数据
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).
当然,这意味着 View 必须有一个无参数的构造函数才能开始(否则设计者将无法实例化它)。
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).
ViewModelLocator 是一种习惯用法,可让您在 MVVM 应用程序中保留 DI 的优势,同时还允许您的代码与视觉设计人员一起使用。这有时称为应用程序的“可混合性”(指 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.
最后,使用数据模板不是使用 ViewModelLocator 的替代方法,而是对部分 UI 使用显式 View/ViewModel 对的替代方法。通常,您可能会发现不需要为 ViewModel 定义视图,因为您可以使用数据模板来代替。
回答by BrunoLM
An example implementation of @Jon's answer
@Jon 答案的示例实现
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.
我有一个视图模型定位器类。每个属性都将是我将在我的视图上分配的视图模型的一个实例。我可以检查代码是否在设计模式下运行或不使用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);
}
}
And to use it I can add my locator to App.xaml
resources:
为了使用它,我可以将我的定位器添加到App.xaml
资源中:
xmlns:core="clr-namespace:MyViewModelLocatorNamespace"
<Application.Resources>
<core:ViewModelLocator x:Key="ViewModelLocator" />
</Application.Resources>
And then to wire up your view (ex: MainView.xaml) to your viewmodel:
然后将您的视图(例如:MainView.xaml)连接到您的视图模型:
<Window ...
DataContext="{Binding Path=MainViewModel, Source={StaticResource ViewModelLocator}}">
回答by hyankov
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):
View Model Locator 的目的是让您的 View 实例化它(是的,View Model Locator = View First):
public void MyWindowViewModel(IService someService)
{
}
instead of just this:
而不仅仅是这个:
public void MyWindowViewModel()
{
}
by declaring this:
通过声明:
DataContext="{Binding MainWindowModel, Source={StaticResource ViewModelLocator}}"
Where ViewModelLocator
is class, which references a IoC and that's how it solves the MainWindowModel
property it exposes.
ViewModelLocator
类在哪里,它引用了一个 IoC,这就是它如何解决MainWindowModel
它公开的属性。
It has nothing to do with providing Mock view models to your view. If you want that, just do
它与为您的视图提供 Mock 视图模型无关。如果你想要,就这样做
d:DataContext="{d:DesignInstance MockViewModels:MockMainWindowModel, IsDesignTimeCreatable=True}"
The View Model Locator is a wrapper around some (any) Inversion of Control container, such as Unity for example.
视图模型定位器是一些(任何)控制反转容器的包装器,例如 Unity。
Refer to:
参考: