WPF的组合指南:MVVM vs MVP

16

我有些困惑,也许你可以帮助我 :)

我一直遵循CAG的指导,并发现MVP模式非常自然。假设我有一个准备好的UI Model(例如:实现INotifyPropertyChanged),我使用Presenter将这个Model绑定到视图上(presenter知道视图的接口),让我的Code-Behind尽可能小,只处理绑定(Model和Commands)属性(或方法)或对于没有ICommand的控件的事件,在这种情况下立即委托给Presenter。

  1. 不久后,我发现了MVVM模式,但至今仍然让我感到困惑。就我所知,在我的方法中,只有当我的Model不是UI-ready时,我才会使用MVVM。但保留Presenter并使用新的Model是否更合理?我不明白这样的使用方式会失去什么。我知道我错过了什么,但是是什么呢:).

  2. 此外,当您的View是通用的,可以处理许多种Models(例如,在PropertyGrid中)。推荐使用ViewModel与DataTemplate配合使用,但在这种情况下,您无法为Model中的每个实体创建模板,需要在运行时进行调查,您会推荐什么呢?

  3. 在观看Josh Smith在screencast中谈论MVVM时,我感到重新在ViewModel中暴露Model会违反DRY(不要重复自己)原则,这真的是不可避免的吗?令我惊讶的是,与ADO.Net Dynamic Data metadata classes最近引起争议相比,没有人对此进行辩论。

希望表述清楚

谢谢

Ariel

4个回答

20

关于第三点,很多人会使用“另一层间接性”的论点,说模型的更改不会影响视图。尽管这在技术上是正确的,但这并不是进行此类操作的真正原因。

如果您将Model视为从数据访问层或服务(通常被认为是这些实体)获取的实体,则开始看到为什么需要ViewModel。ViewModel旨在扩展具有View所需行为的Model

例如,如果您想更改属性并通过绑定使View被通知此更改,则该属性需要引发某种NotifyPropertyChanged。这是您典型Model所没有的行为。

在另一个示例中,假设您有一个集合,并且希望在用户单击视图中的复选标记旁边的每个项目时使用布尔值标记该集合中的每个项目。您可能需要一个“IsSelected”属性。这是Model不应该提供的行为。

然而,我理解您的观点...一开始我确实遇到了这个问题。第一次将Model的内容复制粘贴到我的viewmodel中时,我感到非常不舒服,但您只需要认识到为使您的View工作,它需要这个额外的行为,而Model不应提供它。

无论这有多少不DRY,强制您的WCF类型或LINQ到SQL类型(或任何您喜欢的ORM)实现INotifyProperyChanged都更糟糕。


2
总体来说,回答很棒,但最后一句话真正点燃了它。 - jrista
1
在我们的MVVM实现中,我们仍然使用领域驱动设计的影响编写我们的Model,以及一些从业务对象框架(如已经实现INotifyProperyChanged的CSLA)中学到的东西。由于我们的设计,到目前为止,在我们的ViewModel中我们有更少的Model重复,并且通常只需要在我们需要为View不同地抽象事物时编写相应的ViewModel类,正如Anderson所提到的那样。 - jpierson

6
除了上面的评论以外,我想分享一下我个人对两种模式的理解。
通常情况下,在MVP中,你会有一个View接口,比如IView,来抽象实际的视图并将数据绑定到这些实际的视图上。而在MVVM中,你通常会使用实际视图(例如XAML用户控件)的DataContext来进行数据绑定,这类似于MVP中的IView。因此可以说,这两种模式的绑定方式是相似的。
主要的区别在于Presenter和ViewModel部分。ViewModel与Presenter非常不同,Presenter是UI和模型之间交换数据的桥梁。它实际上就像其名字所表示的那样,是视图的模型。ViewModel中暴露的数据主要用于UI处理。因此在我的理解中,在MVVM中,ViewModel是视图的抽象表示。与此相反,MVP主要使用IView来抽象视图。因此,在MVVM中通常比MVP具有更少的层次,因此你可以写更少的代码来完成相同的工作:
MVVM:Model - ViewModel(代表实际视图,即UI) - 实际视图
MVP:Model - Presenter(用于在模型和UI之间交换数据的桥梁) - IView(代表实际视图,即UI) - 实际视图
MVVM相对于MVP的优势主要基于Microsoft产品中以下两个重要的功能:
1. WPF中的命令,尽管现在已经有了一些实现并不在Silverlight运行时中
2. WPF和Silverlight中的DataContext。

6

第三点。在ViewModel中暴露Model可能会让你觉得自己在重复,但实际上你所做的是将Model抽象化,以便View只知道这种抽象(View只知道ViewModel)。

这是因为对Model的更改不应该破坏View。此外,您的Model可以作为许多从不同来源获取数据的不同服务来实现。在这种情况下,您不希望View知道所有这些服务,因此创建另一个抽象 - ViewModel。


5
如果Presenter知道View的接口,则需要所有Presenter使用的View具有相同的接口或为每个View创建一个Presenter。使用MVVM,View知道ViewModel,而ViewModel知道Model(但反之不然)。这意味着多个View可以使用VM,多个VM可以使用Model。
我不太确定您在第二点中所询问的内容。VM不是View(也不知道View),对我而言,DataTemplate定义了如何显示对象。我将我的DataTemplates放在ResourceDictionary中,这明确属于View。在我的VM层中,唯一的WPF“东西”是Commands。
我需要更多信息才能回答您的第三点。也许如果您深入了解MVVM,它会自己解答。 这是我的一篇相关文章,可能会对您有所帮助 祝好运。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接