许多人建议WPF MVVM开发人员不要将Model实例从ViewModel暴露给View。要显示模型实例集合中的信息,请将所有单个项目包装到ViewModel实例中,并将ViewModel集合公开给View。
但是,使用MVVM Light在我看来有两种ViewModels:
MainWindowViewModel
或CustomerEditorViewModel
)。假设只有一个MainWindow
,则只有一个MainWindowViewModel
。CustomerViewModel
)并且是某种" mech suit"对于模型实例,提供其他功能,例如计算属性(例如Duration
和StartTime
中的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:
MainViewModel
已在ViewModelLocator
注册,并且没有构造函数参数。因此它适用于依赖注入,可以通过ServiceLocator实例化。FriendViewModel
未在ViewModelLocator
中注册,其构造函数将Model实例作为参数。它不能通过ServiceLocator实例化,而只能通过直接调用构造函数并传递模型实例来实现。这几乎与我原始问题中提到的差异一致,并且第一个想法是如何包装模型实例。
答案 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:
更详细地说,这就是它们的结构。请注意,“EmployeeViewModel”没有“EmployeeView”。同样,这些“屏幕”视图模型根本没有任何模型,它们并不真正与数据对象相关联,并且不需要模型:
如果我们只绑定直接数据项(并且没有其他View相关逻辑,比如说“隐藏”属性来显示/隐藏我们的员工)那么我们就不需要EmployeeViewModel了,我们可以绑定我们的EmployeeTrackerScreenViewModel到许多EmployeeModel。