简体   繁体   English

MVVM Light中有两种ViewModel吗?

[英]Are there two kinds of ViewModels in MVVM Light?

Many people advice WPF MVVM developers to not expose Model instances from the ViewModel to the View. 许多人建议WPF MVVM开发人员不要将Model实例从ViewModel暴露给View。 To display the information from a collection of Model instances, wrap all individual items into ViewModel instances and expose a collection of ViewModels to the View. 要显示模型实例集合中的信息,请将所有单个项目包装到ViewModel实例中,并将ViewModel集合公开给View。

However, using MVVM Light it seems to me there are two kinds of ViewModels then: 但是,使用MVVM Light在我看来有两种ViewModel:

  • ViewModels that have a one-to-one relationship with a view (eg MainWindowViewModel or CustomerEditorViewModel ). 与视图具有一对一关系的ViewModel(例如MainWindowViewModelCustomerEditorViewModel )。 Assumed there is only one MainWindow , there will only be one MainWindowViewModel . 假设只有一个MainWindow ,那么只有一个MainWindowViewModel
  • ViewModels that have a one-to-one relationship with a model instance (eg CustomerViewModel ) and are some kind of "mech suit" for the model instance, providing additional functionality like calculated properties (eg Duration from StartTime and EndTime ). 与模型实例(例如CustomerViewModel )具有一对一关系的ViewModel,它是模型实例的某种“机制套装”,提供计算属性等附加功能(例如StartTimeEndTime Duration )。 A usual company has many Customer s so there will be many CustomerViewModel s. 一个普通的公司有很多Customer所以会有很多CustomerViewModel

How to wrap Model instances then? 那么如何包装Model实例呢?

One idea could be to create wrapper classes deriving from ViewModelBase but not registering and instantiating those with the ViewModelLocator . 一个想法可能是创建从ViewModelBase派生但不使用ViewModelLocator注册和实例化那些包装类。 I do not think it is a good idea to have two seperate things both called ViewModel. 我认为两个单独的东西都叫做ViewModel并不是一个好主意。

Another idea could be to use a new base class for the second type of ViewModels, maybe called ModelInfo . 另一个想法可能是为第二种类型的ViewModel使用新的基类,可能称为ModelInfo In a single instance of MainViewModel there would be a collection of CustomerInfo instances, providing the additional functionality for the Customer model data. MainViewModel的单个实例中,将存在CustomerInfo实例的集合,为Customer模型数据提供附加功能。

I would tend to the latter but as this seems to be a pretty general case using MVVM Light, I am sure there must be a common solution to this issue. 我倾向于后者,但因为这似乎是使用MVVM Light的一般情况,我相信必须有一个共同的解决方案来解决这个问题。


Update 更新

I have found an article by Laurent Bugnion , the author of MVVM Light. 我找到 MVVM Light的作者Laurent Bugnion的一篇文章 In his article from the year 2012 Bugnion uses two different approaches of initializing ViewModels: 在他2012年的文章中,Bugnion使用两种不同的方法来初始化ViewModel:

  1. MainViewModel is registered with the ViewModelLocator and has no constructor arguments. MainViewModel已向ViewModelLocator注册,并且没有构造函数参数。 Thus it is suitable for Dependency Injection and can be instantiated through the ServiceLocator. 因此它适用于依赖注入,可以通过ServiceLocator实例化。
  2. FriendViewModel is not registered with the ViewModelLocator and its constructor takes a Model instance as an argument. FriendViewModel未向ViewModelLocator注册,其构造函数将Model实例作为参数。 It can not be instantiated with the ServiceLocator but only by directly calling the constructor and passing the model instance. 它不能使用ServiceLocator进行实例化,而只能通过直接调用构造函数并传递模型实例来实例化。

This pretty much aligns with the differentiation mentioned in my original question, and with the first idea how to wrap model instances then. 这几乎与我原始问题中提到的差异一致,并且第一个想法是如何包装模型实例。

Here is my personal 7 years experience with MVVM. 这是我个人7年的MVVM经验。 I say personal because you will find a lot of contradiction on this topic, especially when you refer to the official MSDN definition 我说个人是因为你会发现很多关于这个话题的矛盾,特别是当你参考官方的MSDN定义时

"it seems to me there are two kinds of ViewModels" “在我看来,有两种ViewModels”

Absolutely not, but it is a common misunderstanding. 绝对不是,但这是一个常见的误解。 The first role of a ViewModel is to be a testable and maintainable representation of your View. ViewModel的第一个角色是View的可测试和可维护的表示。 The correct abstraction is then a one-one relationship with your view, not your Model. 然后,正确的抽象是与您的视图的一对一关系,而不是您的模型。

"Many people advice WPF MVVM developers to not expose Model instances from the ViewModel to the View." “许多人建议WPF MVVM开发人员不要将Model实例从ViewModel暴露给View。”

Yes, it is still true, because if your Model is correctly implemented from an OOP perspective, you put the responsibility and business logic inside it. 是的,它仍然是正确的,因为如果从OOP角度正确实现模型,则将责任和业务逻辑放在其中。 Thus your ViewModel is just INotifiedPropertyChanged , and wrap the information you want to expose from your Model, and the command you want to call in your Model. 因此,您的ViewModel只是INotifiedPropertyChanged ,并包含您要从模型中公开的信息,以及要模型中调用的命令。

The classic explanation (including MSDN's one) is incomplete, because it assumes you can align one View with one ViewModel with one Model. 经典解释(包括MSDN的解释)是不完整的,因为它假设您可以将一个View与一个ViewModel与一个Model对齐。 Thus your problem is often overlooked, because in a very CRUD system, you can easily have this one-to-one-to-one relationship. 因此,您的问题经常被忽视,因为在非常简单的CRUD系统中,您可以轻松实现这种一对一的关系。 Another way to have this relationship is to use CQRS , because it allows you to generate a Model without any logic and directly aligned on your view for query. 建立这种关系的另一种方法是使用CQRS ,因为它允许您生成一个没有任何逻辑的模型,并直接在您的视图上对齐以进行查询。

But as you already experienced (if you don't work on a CRUD or CQRS system), in most classic implementation, your ViewModel represents your View, but needs several Models to work well (which is perfectly natural). 但正如您已经体验过的那样(如果您不使用CRUD或CQRS系统),在大多数经典实现中,您的ViewModel代表您的View,但需要多个模型才能正常工作(这非常自然)。 You have to put as much business logic as you can in these Models. 您必须在这些模型中添加尽可能多的业务逻辑。 And to manage the flow between calls to your different Models, you add another abstraction, which could be called a Service. 为了管理对不同模型的调用之间的流程,您可以添加另一个抽象,可以称为服务。 This Service should represent a business case, which need to use several Models. 此服务应代表业务案例,需要使用多个模型。

You can think about it in this way: your BusinessService should work independently of the infrastructure. 您可以通过这种方式考虑它:您的BusinessService应独立于基础架构工作。 It should not care if it's called from a ViewModel, or from a Controller in a Web App. 它不应该关心它是从ViewModel调用还是从Web应用程序中的Controller调用。 It just manages the flow between some Models to meet a business need. 它只是管理一些模型之间的流程,以满足业务需求。

Let me try recap: 让我试试一下:

  • A ViewModel should not have business logic (but you already get that) ViewModel不应该有业务逻辑(但你已经得到了)

  • A ViewModel is an abstraction of your View (and not of your Model, even if in some cases you can obtain a one-to-one-to-one relationship) ViewModel是View的抽象(而不是您的Model的抽象,即使在某些情况下您可以获得一对一的关系)

  • If a ViewModel needs several Models to meet a Business need, use a Service to manage the flow between your different models (it becomes by definition a BusinessService) 如果ViewModel需要多个模型来满足业务需求,请使用服务来管理不同模型之间的流程(根据定义,它变为BusinessService)

Here is a blog post with code example to clarify my point: http://ouarzy.azurewebsites.net/2016/04/14/clarifying-mvvm-with-ddd/ 这是一篇博客文章,其中包含代码示例以澄清我的观点: http//ouarzy.azurewebsites.net/2016/04/14/clarifying-mvvm-with-ddd/

Hope it helps. 希望能帮助到你。

From what I can gather, as above a ViewModel has a one-to-one relationship with a View. 从我可以收集到的内容,如上所述,ViewModel与View具有一对一的关系。

In practice, I find I use ViewModels without their view - usually when displaying a collection of them using ItemsSource. 在实践中,我发现我在没有视图的情况下使用ViewModels - 通常在使用ItemsSource显示它们的集合时。 If it needs it, I'll have an ItemsSource of views - but if it's something very simple I'll just use the "parent" view. 如果它需要它,我将有一个ItemsSource视图 - 但如果它非常简单,我将只使用“父”视图。 Not sure if this is best practice, but there comes a point where you need to bind to something other than the Model's plain properties and need View related properties to bind to, but a dedicated view doesn't make sense (in a DataGrid row for example, a Row might be a ViewModel, but has no View). 不确定这是否是最佳实践,但有一点需要绑定到Model的普通属性之外的东西,并且需要View相关属性来绑定,但是专用视图没有意义(在DataGrid行中为例如,一行可能是ViewModel,但没有View)。

Here's an example of what I'm talking about. 这是我正在谈论的一个例子。 A random example app has three "Main" ViewModels and Views: 随机示例应用程序有三个“主”ViewModel和Views:

在此输入图像描述

In more detail, this is how they are structured. 更详细地说,这就是它们的结构。 Note there's no "EmployeeView" for the "EmployeeViewModel". 请注意,“EmployeeViewModel”没有“EmployeeView”。 Similarly, these "Screen" view models don't have any models at all, they're not really associated with a data object and a model isn't needed: 同样,这些“屏幕”视图模型根本没有任何模型,它们并不真正与数据对象相关联,并且不需要模型:

在此输入图像描述

If we were only binding to straight up data items (and had no other View related logic, like say a "Hidden" property to show/hide our employees) then we wouldn't need an EmployeeViewModel, we could just bind our EmployeeTrackerScreenViewModel to many EmployeeModels. 如果我们只绑定到直接数据项(并且没有其他View相关逻辑,比如说“隐藏”属性来显示/隐藏我们的员工)那么我们就不需要EmployeeViewModel,我们可以将EmployeeTrackerScreenViewModel绑定到许多EmployeeModels。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM