c# - MVVM Light 中有两种 ViewModel 吗?

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

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

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

  • 与 View 具有一对一关系的 ViewModel(例如 MainWindowViewModelCustomerEditorViewModel)。假设只有一个MainWindow,那么也就只有一个MainWindowViewModel
  • 与模型实例具有一对一关系的 ViewModel(例如 CustomerViewModel)并且是模型实例的某种“机甲套装”,提供额外的功能,如计算属性(例如Duration 来自 StartTimeEndTime)。通常的公司有很多 Customer,所以会有很多 CustomerViewModel

那如何包装模型实例呢?

一个想法可能是创建从 ViewModelBase 派生的包装类,但不使用 ViewModelLocator 注册和实例化它们。我认为将两个独立的东西都称为 ViewModel 不是一个好主意。

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

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


更新

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

  1. MainViewModel 注册到 ViewModelLocator 并且没有构造函数参数。因此它适用于依赖注入(inject),可以通过ServiceLocator实例化。
  2. FriendViewModel 未在 ViewModelLocator 中注册,其构造函数将 Model 实例作为参数。它不能用 ServiceLocator 实例化,只能通过直接调用构造函数并传递模型实例来实例化。

这与我在最初的问题中提到的区别非常吻合,并且与当时如何包装模型实例的第一个想法一致。

最佳答案

这是我个人 7 年的 MVVM 经验。我说个人是因为你会发现这个话题有很多矛盾,尤其是当你引用官方的时候MSDN definition

"it seems to me there are two kinds of ViewModels"

绝对不是,但这是一个普遍的误解。 ViewModel 的第一个角色是成为 View 的可测试和可维护的表示。正确的抽象是与您的 View 的一对一关系,而不是您的模型。

"Many people advice WPF MVVM developers to not expose Model instances from the ViewModel to the View."

是的,这仍然是正确的,因为如果您的模型是从 OOP 正确实现的perspective,你把职责和业务逻辑放在里面。因此,您的 ViewModel 只是INotifiedPropertyChanged,并包装您希望您的模型公开的信息,以及您希望您的模型中调用的命令.

经典解释(包括 MSDN 的解释)是不完整的,因为它假定您可以将一个 View 与一个 View 模型与一个模型对齐。因此你的问题经常被忽视,因为在一个非常 CRUD 的系统中,你可以很容易地拥有这种一对一的关系。另一种建立这种关系的方法是使用 CQRS ,因为它允许您生成一个没有任何逻辑的模型,并直接在您的 View 上对齐以供查询。

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

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

让我试着回顾一下:

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

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

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

这是一篇带有代码示例的博文来阐明我的观点: http://ouarzy.azurewebsites.net/2016/04/14/clarifying-mvvm-with-ddd/

希望对您有所帮助。

关于c# - MVVM Light 中有两种 ViewModel 吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36421382/

相关文章:

c# - Linq - 里面包括

c# - 只有一个 C# 事件处理程序被调用

C# WPF 为列表中的每个对象动态创建一个 GUI 元素

c# - SqlDependency - 防止事件之间的数据丢失并再次重新注册查询?

wpf - MVVM:仅在数据有效时使绑定(bind)更新 ViewModel

c# - XAML 基于绑定(bind)改变框架背景

c# - 套接字编程 : The Server

C# 和 MySQL - 返回 DataReader(或其内容)的方法

C# WPF Xaml : Globally set all text in a view to one color, 和所有背景到另一个

c# - 在组标题 WPF 中显示 "filled"行的数量