许多人建议 WPF MVVM 开发人员不要将 ViewModel 中的 Model 实例暴露给 View。要显示来自 Model 实例集合的信息,请将所有单个项目包装到 ViewModel 实例中,并将 ViewModel 集合公开给 View。
但是,在我看来,使用 MVVM Light 有两种 ViewModel:
- 与 View 具有一对一关系的 ViewModel(例如
MainWindowViewModel
或CustomerEditorViewModel
)。假设只有一个MainWindow
,那么也就只有一个MainWindowViewModel
。 - 与模型实例具有一对一关系的 ViewModel(例如
CustomerViewModel
)并且是模型实例的某种“机甲套装”,提供额外的功能,如计算属性(例如Duration
来自StartTime
和EndTime
)。通常的公司有很多Customer
,所以会有很多CustomerViewModel
。
那如何包装模型实例呢?
一个想法可能是创建从 ViewModelBase
派生的包装类,但不使用 ViewModelLocator
注册和实例化它们。我认为将两个独立的东西都称为 ViewModel 不是一个好主意。
另一个想法可能是为第二种类型的 ViewModel 使用一个新的基类,可能称为 ModelInfo
。在 MainViewModel
的单个实例中,会有一组 CustomerInfo
实例,为 Customer
模型数据提供附加功能。
我倾向于后者,但由于这似乎是使用 MVVM Light 的一个非常普遍的情况,我相信必须有一个通用的解决方案来解决这个问题。
更新
我找到了 an article by Laurent Bugnion ,MVVM Light 的作者。 在他 2012 年的文章中,Bugnion 使用了两种不同的初始化 ViewModel 的方法:
MainViewModel
注册到ViewModelLocator
并且没有构造函数参数。因此它适用于依赖注入(inject),可以通过ServiceLocator实例化。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/