MVVM Light中有两种ViewModel吗?

时间:2016-04-05 08:47:15

标签: c# wpf mvvm entity-framework-6 mvvm-light

许多人建议WPF MVVM开发人员不要将Model实例从ViewModel暴露给View。要显示模型实例集合中的信息,请将所有单个项目包装到ViewModel实例中,并将ViewModel集合公开给View。

但是,使用MVVM Light在我看来有两种ViewModels:

  • 与视图具有一对一关系的ViewModel(例如MainWindowViewModelCustomerEditorViewModel)。假设只有一个MainWindow,则只有一个MainWindowViewModel
  • 与模型实例具有一对一关系的ViewModel(例如CustomerViewModel)并且是某种" mech suit"对于模型实例,提供其他功能,例如计算属性(例如DurationStartTime中的EndTime。一个普通公司有很多Customer s因此会有很多CustomerViewModel s。

如何包装模型实例呢?

一个想法可能是创建从ViewModelBase派生的包装类,但不注册和实例化ViewModelLocator的包装类。我不认为有两个单独的东西叫做ViewModel是个好主意。

另一个想法可能是为第二种类型的ViewModel使用新的基类,可能称为ModelInfo。在MainViewModel的单个实例中,会有一组CustomerInfo个实例,为Customer模型数据提供附加功能。

我倾向于后者,但由于这似乎是使用MVVM Light的一般情况,我相信必须有一个共同的解决方案来解决这个问题。

更新

我找到了MVVM Light的作者an article by Laurent Bugnion。 在他2012年的文章中,Bugnion使用两种不同的方法来初始化ViewModels:

  1. MainViewModel已在ViewModelLocator注册,并且没有构造函数参数。因此它适用于依赖注入,可以通过ServiceLocator实例化。
  2. FriendViewModel未在ViewModelLocator中注册,其构造函数将Model实例作为参数。它不能通过ServiceLocator实例化,而只能通过直接调用构造函数并传递模型实例来实现。
  3. 这几乎与我原始问题中提到的差异一致,并且第一个想法是如何包装模型实例。

2 个答案:

答案 0 :(得分:9)

这是我个人7年的MVVM经验。我说个人是因为你会发现很多关于这个话题的矛盾,特别是当你提到官方MSDN definition

  

“在我看来,有两种ViewModels”

绝对不是,但这是一种常见的误解。 ViewModel的第一个角色是View的可测试和可维护的表示。然后,正确的抽象是与您的视图的一对一关系,而不是您的模型。

  

“许多人建议WPF MVVM开发人员不要公开Model实例   从ViewModel到View。“

是的,它仍然是正确的,因为如果从OOP角度正确实现模型,则将责任和业务逻辑放在其中。因此,您的ViewModel只是 INotifiedPropertyChanged ,并包含您希望公开来自模型的信息,以及要在模型中调用的命令

经典解释(包括MSDN的解释)是不完整的,因为它假设您可以将一个View与一个ViewModel与一个Model对齐。因此,您的问题经常被忽视,因为在非常简单的CRUD系统中,您可以轻松实现这种一对一的关系。建立这种关系的另一种方法是使用CQRS,因为它允许您生成一个没有任何逻辑的模型,并直接在您的视图上对齐以进行查询。

但正如您已经体验到的那样(如果您不使用CRUD或CQRS系统),在大多数经典实现中,您的ViewModel代表您的View,但需要多个模型才能正常工作(这非常自然)。您必须在这些模型中添加尽可能多的业务逻辑。为了管理对不同模型的调用之间的流程,您可以添加另一个抽象,可以称为服务。此服务应代表一个商业案例,需要使用多个模型。

您可以通过这种方式考虑它:您的BusinessService应独立于基础架构工作。它不应该关心它是从ViewModel调用还是从Web应用程序中的Controller调用。它只是管理一些模型之间的流程,以满足业务需求。

让我试一下:

  • ViewModel不应该有业务逻辑(但你已经得到了)

  • ViewModel是您的View的抽象(而不是您的模型的抽象,即使在某些情况下您可以获得一对一的关系)

  • 如果ViewModel需要多个模型来满足业务需求,请使用服务来管理不同模型之间的流程(根据定义成为BusinessService)

这是一篇博客文章,其中包含代码示例,以阐明我的观点: http://ouarzy.azurewebsites.net/2016/04/14/clarifying-mvvm-with-ddd/

希望它有所帮助。

答案 1 :(得分:1)

从我可以收集到的内容,如上所述,ViewModel与View具有一对一的关系。

在实践中,我发现我在没有视图的情况下使用ViewModels - 通常在使用ItemsSource显示它们的集合时。如果它需要它,我将有一个ItemsSource视图 - 但如果它非常简单,我将只使用“父”视图。不确定这是否是最佳实践,但有一点需要绑定到Model的普通属性之外的东西,并且需要View相关属性来绑定,但是专用视图没有意义(在DataGrid行中为例如,一行可能是ViewModel,但没有View。。

这是我正在谈论的一个例子。随机示例应用程序有三个“主”ViewModel和Views:

enter image description here

更详细地说,这就是它们的结构。请注意,“EmployeeViewModel”没有“EmployeeView”。同样,这些“屏幕”视图模型根本没有任何模型,它们并不真正与数据对象相关联,并且不需要模型:

enter image description here

如果我们只绑定直接数据项(并且没有其他View相关逻辑,比如说“隐藏”属性来显示/隐藏我们的员工)那么我们就不需要EmployeeViewModel了,我们可以绑定我们的EmployeeTrackerScreenViewModel到许多EmployeeModel。