WPF - MVVM 视图模型优先
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/28434476/
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
WPF - MVVM view model first
提问by user2429022
I am building a large scale WPF app - kind of a desktop that hosts multiple modules such as multiple Terminal windows over RS232/Ethernet, Register analyzer, automation tools, etc. I am working with MVVM architecture where my view (XAML) instantiate the corespondent viewmodel in its resource section. and the view model is set in the data-context of the view. in this method the view created first.
我正在构建一个大型 WPF 应用程序 - 一种托管多个模块的桌面,例如通过 RS232/以太网的多个终端窗口、注册分析器、自动化工具等。我正在使用 MVVM 架构,其中我的视图 (XAML) 实例化了通信方viewmodel 在其资源部分。并且视图模型设置在视图的数据上下文中。在这种方法中,首先创建了视图。
however, I red about another method called VM first, meaning view model is instantiated before the view, and I understood the theory that stands behind it. What I didn't understand is when and who instantiate the view and how it happens without coupling to the view.
但是,我首先想到了另一种称为 VM 的方法,这意味着在视图之前实例化了视图模型,并且我理解了它背后的理论。我不明白的是什么时候和谁实例化了视图,以及它是如何在不耦合到视图的情况下发生的。
I'll be more than happy to hear your thoughts, and please if someone can supply code samples it would be great..
我会很高兴听到您的想法,如果有人可以提供代码示例,那就太好了。
Thanks in advance.
提前致谢。
回答by Martin Moser
I'm using MVVM heavily in my projects and can share my view on this. In my projects the view neverinstantiates any VM. Usually I have some kind of manager which takes care that the corresponding VM is created.
我在我的项目中大量使用 MVVM,可以分享我对此的看法。在我的项目中,视图从不实例化任何 VM。通常我有某种管理器负责创建相应的 VM。
This I'm assign to the datacontext of some top-level UI control (Window for instance). The view is always defined by a style where the target type is set to the type of the view model. The startup code just creates a Window and the main viewmodel. The VM is assigned and the rest is done by the WPF (.net) runtime so to say.
我将此分配给某些顶级 UI 控件(例如 Window)的数据上下文。视图始终由一种样式定义,其中目标类型设置为视图模型的类型。启动代码只是创建了一个 Window 和主视图模型。VM 已分配,其余部分由 WPF (.net) 运行时完成。
So I have a large style file, where all the styles for each viewmodel defines the corresponding view (usually a usercontrol).
所以我有一个很大的样式文件,其中每个视图模型的所有样式都定义了相应的视图(通常是用户控件)。
This is the way I'm doing things, there are for sure others too.
这就是我做事的方式,当然也有其他人。
hth
第
回答by Tim Rogers
To decouple the view from the view-model, something else needs to instantiate the view model and manage its lifetime and sharing. That job might fall to an IoC container, or simple, manual dependency injection. It's entirely up to you.
为了将视图与视图模型解耦,还需要其他东西来实例化视图模型并管理其生命周期和共享。这项工作可能属于 IoC 容器,或者简单的手动依赖注入。这完全取决于你。
E.g. from Paul Stovell's article:
例如来自Paul Stovell 的文章:
public CalculatorView(CalculatorViewModel viewModel)
{
InitializeComponent();
DataContext = viewModel;
}
It all depends on you're trying to achieve by decoupling. One reason might be so that you can have multiple views over the same view-model - in that case, whatever creates the views needs to also create the view-model.
这一切都取决于你试图通过解耦来实现。一个原因可能是您可以在同一个视图模型上拥有多个视图 - 在这种情况下,创建视图的任何内容都需要创建视图模型。
Another may be to swap the view-model of an existing view out with another view-model without destroying the view. In that case, maybe you already have two existing view-models and you assign them to the view's DataContextas required.
另一种可能是在不破坏视图的情况下用另一个视图模型交换现有视图的视图模型。在这种情况下,也许您已经有两个现有的视图模型,并DataContext根据需要将它们分配给视图。
view.DataContext = viewModels[0];
view.DataContext = viewModels[1];
回答by silverfighter
when your application grows you usually face these decisions. Usually you have "always"both elements together the Viewand the ViewModelit's not about what comes first it's more like what will you use to instantiate the two elements (viewand viewmodel).
For larger projects, when I had the need, I used a class called ViewModelResolver. It obviously has an interface IViewModelResolverso it can be injected nicely.
It can either return a ViewModelbased on convention based on type or a string representation and uses reflection to instantiated it.
You can also pass in a ViewModel(or type) and get the matching viewwith the passed in view modelas DataContext(view ViewModel marriage) or you can define other custom scenarios that you need for instantiating either viewor ViewModel.
当您的应用程序增长时,您通常会面临这些决定。通常,您将两个元素“始终”放在一起,View并且ViewModel这与先出现的内容无关,而更像是您将使用什么来实例化这两个元素(view和viewmodel)。对于较大的项目,当我需要时,我使用了一个名为ViewModelResolver. 它显然有一个接口,IViewModelResolver因此可以很好地注入。它可以返回ViewModel基于类型的约定或字符串表示,并使用反射来实例化它。您还可以传入 a ViewModel(或类型)并view与传入的view modelas匹配DataContext(查看 ViewModel 婚姻),或者您可以定义实例化所需的其他自定义场景view或ViewModel。
hope that helps
希望有帮助
So the main point is to have an intermediate class that acts like some sort of factory service that takes car of bringing views and view models together and instantiate them. This gives you more freedom and a good place to separate out those decisions from the ViewModel directly.
所以重点是有一个中间类,它就像某种工厂服务,负责将视图和视图模型放在一起并实例化它们。这给了你更多的自由和一个很好的地方来直接从 ViewModel 中分离这些决定。
回答by Peregrine
In my WPF / MVVM applications I use ViewModels with two constructors - one for design time (no paramaters - mock version of required components are set directly) and another for runtime (required components are injected as parameters via IoC). This allows for (mock) data to be displayed inside the Visual Studio designer for UI testing purposes.
在我的 WPF / MVVM 应用程序中,我使用带有两个构造函数的 ViewModel - 一个用于设计时(无参数 - 直接设置所需组件的模拟版本),另一个用于运行时(所需组件通过 IoC 作为参数注入)。这允许(模拟)数据显示在 Visual Studio 设计器中以进行 UI 测试。
So the simple case looks like ...
所以这个简单的案例看起来像......
public class MainViewModel : ViewModelBase
{
private IDataFactory _DataFactory;
public MainViewModel()
{
_DataFactory = new DesignTimeMockDataFactory();
LoadData();
}
[PreferredConstructor]
public MainViewModel(IDataFactory dataFactory)
{ _DataFactory = dataFactory; }
public void LoadData()
{ DataItems.AddRange(_DataFactory.GetDataItems()); }
public ExtendedObservableCollection<DataItem> DataItems { get; private set; }
}
The design time usage can be set directly in the XAML ...
设计时使用可以直接在 XAML 中设置...
<Window x:Class="MainView"
d:DataContext="{d:DesignInstance Type=MainViewModel, IsDesignTimeCreatable=True}"
...
The run-time ViewModel is set in the code behind of the View ...
运行时 ViewModel 设置在 View 后面的代码中...
public MainView()
{
InitializeComponent();
var viewModel = SimpleIoc.Default.GetInstance<MainViewModel>();
DataContext = viewModel;
Loaded += (s, e) => viewModel.LoadData();
}
The View's Loaded event is set to call the LoadData() method of the ViewModel to trigger data loading, once the View is displayed. If LoadData() is slow, it can be changed into an async method to prevent the UI from blocking.
View的Loaded事件设置为调用ViewModel的LoadData()方法触发数据加载,一旦View显示出来。如果 LoadData() 很慢,可以将其更改为异步方法以防止 UI 阻塞。
For those of you complaining that this is a too tightly coupled construct, my view is that is exactly how they are supposed to be. Although the View and ViewModel are separate entities, each View knows exactly what type of ViewModel it requires, and that's unlikely to change over the project development life-cycle. Using a Locator type class to hide the ViewModel constructor calls is an unnecessary level of abstraction in my opinion.
对于那些抱怨这是一个过于紧密耦合的结构的人,我的观点是他们应该是这样。尽管 View 和 ViewModel 是独立的实体,但每个 View 都确切地知道它需要什么类型的 ViewModel,并且在项目开发生命周期中不太可能改变。在我看来,使用 Locator 类型类来隐藏 ViewModel 构造函数调用是不必要的抽象级别。

