首页 文章

MVVM Light中有两种ViewModel吗?

提问于
浏览
4

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

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

  • 与视图具有一对一关系的ViewModel(例如 MainWindowViewModelCustomerEditorViewModel ) . 假设只有一个 MainWindow ,那么只有一个 MainWindowViewModel .

  • 与模型实例具有一对一关系的ViewModel(例如 CustomerViewModel ),并且是模型实例的某种"mech suit",提供了计算属性等附加功能(例如,来自 StartTimeEndTimeDuration ) . 一个普通的公司有很多 Customer s所以会有很多 CustomerViewModel s .

How to wrap Model instances then?

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

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

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


Update

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

  • MainViewModel 已在 ViewModelLocator 中注册,并且没有构造函数参数 . 因此它适用于依赖注入,可以通过ServiceLocator实例化 .

  • FriendViewModel 未在 ViewModelLocator 中注册,其构造函数将Model实例作为参数 . 它不能使用ServiceLocator进行实例化,而只能通过直接调用构造函数并传递模型实例来实例化 .

这几乎与我原始问题中提到的差异一致,并且第一个想法是如何包装模型实例 .

2 回答

  • 1

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

    “在我看来,有两种ViewModels”

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

    “许多人建议WPF MVVM开发人员不要将Model实例从ViewModel暴露给View . ”

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

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

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

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

    让我试试一下:

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

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

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

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

    希望能帮助到你 .

  • 9

    从我可以收集到的内容,如上所述,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绑定到许多EmployeeModels .

相关问题