C# MVVM Light中有两种ViewModel吗?

C# MVVM Light中有两种ViewModel吗?,c#,wpf,mvvm,entity-framework-6,mvvm-light,C#,Wpf,Mvvm,Entity Framework 6,Mvvm Light,许多人建议WPF MVVM开发人员不要将模型实例从ViewModel公开到视图。要显示模型实例集合中的信息,请将所有单个项包装到ViewModel实例中,并将ViewModels集合公开给视图 然而,在我看来,使用MVVM Light有两种ViewModel: 与视图具有一对一关系的视图模型(例如,MainWindowViewModel或CustomerEditor或ViewModel)。假设只有一个MainWindow,则只有一个MainWindowViewModel 视图模型与模型实例(例

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

然而,在我看来,使用MVVM Light有两种ViewModel:

  • 与视图具有一对一关系的视图模型(例如,
    MainWindowViewModel
    CustomerEditor或ViewModel
    )。假设只有一个
    MainWindow
    ,则只有一个
    MainWindowViewModel
  • 视图模型与模型实例(例如
    CustomerServiceWModel
    )具有一对一关系,并且是模型实例的某种“机械套装”,提供计算属性等附加功能(例如
    开始时间
    结束时间
    )。一个普通的公司有许多
    客户
    s,因此将有许多
    客户服务模型
    s
那么如何包装模型实例?

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

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

我倾向于后者,但由于这似乎是使用MVVM Light的一个相当普遍的情况,我确信对于这个问题一定有一个通用的解决方案


更新

我发现,MVVM Light的作者。 Bugnon在2012年的文章中使用了两种不同的初始化ViewModels的方法:

  • MainViewModel
    使用
    ViewModelLocator
    注册,并且没有构造函数参数。因此,它适合于依赖项注入,并且可以通过ServiceLocator进行实例化
  • FriendViewModel
    未向
    ViewModelLocator
    注册,其构造函数将模型实例作为参数。它不能用ServiceLocator实例化,只能通过直接调用构造函数并传递模型实例来实例化

  • 这与我在最初的问题中提到的差异非常吻合,也与第一个如何包装模型实例的想法非常吻合。

    以下是我个人7年的MVVM经验。我说的是个人的,因为你会发现在这个话题上有很多矛盾,特别是当你提到官方的时候

    “在我看来,有两种视图模型”

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

    “许多人建议WPF MVVM开发人员不要公开模型实例 从视图模型到视图。”

    是的,这仍然是正确的,因为如果您的模型从一个角度正确实现,那么您将责任和业务逻辑放在其中。因此,您的ViewModel只是InotifiedProperty更改,并包装您想从您的模型中公开的信息,以及您想在您的模型中调用的命令

    经典的解释(包括MSDN的解释)是不完整的,因为它假设您可以将一个视图与一个视图模型与一个模型对齐。因此,您的问题经常被忽略,因为在一个非常粗糙的系统中,您可以很容易地建立这种一对一的关系。建立这种关系的另一种方法是使用,因为它允许您在不使用任何逻辑的情况下生成模型,并直接在视图上对齐以进行查询

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

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

    让我重述一下:

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

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

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

    下面是一篇带有代码示例的博客文章,以阐明我的观点:


    希望有帮助。

    从我收集的信息来看,如上所述,ViewModel与视图之间存在一对一的关系

    在实践中,我发现我使用的ViewModel没有它们的视图-通常是在使用ItemsSource显示它们的集合时。如果它需要它,我会有一个ItemsSource视图-但是如果它非常简单,我只会使用“parent”视图。不确定这是否是最佳实践,但有时您需要绑定到模型的普通属性以外的其他属性,并且需要绑定到与视图相关的属性,但专用视图没有意义(在DataGrid行中)