MVVM的基本概念-ViewModel应该做什么?


83

为了掌握MVVM的概念,我已经阅读了几个博客,并研究了一些项目。

据我了解,一个视图是愚蠢的,它只知道如何呈现传递给它的东西。

模型只是纯数据,而ViewModel的作用类似于两者之间的填充,它应该从Model中获取信息并将其传递给View,并且View应该知道如何呈现它。否则,如果View中的信息发生更改,则应将更改传递给Model

但是我仍然不知道如何应用这个概念。有人可以解释一个非常简单的情况,以便我可以理解这个概念吗?我已经看过几个项目,但是仍然没有完全意义,因此,如果有人可以用简单的英语写出来,那就太好了。


2
不能同意以下观点:“只知道如何展示传递给它的东西”。View从VM获取数据。没有人将数据传递给它。没有人知道观点。这是与MVP的重要区别。在MVP中(您可以将其视为具有代码隐藏逻辑的简单WPF应用程序,它是MVP模式),代码隐藏是一个演示者,可以将数据传递到您所说的View。
Grigory

Answers:


146

我喜欢这样想:

正如您所说,观点是愚蠢的。在MVVM上具有开创性且经常相互联系的MSDN文章的作者约什·史密斯(Josh Smith)说,视图是“数据所穿的衣服”。视图从不实际包含或直接处理数据,它们仅绑定到视图模型的属性和命令。

模型是在业务对象中为应用程序域建模对象。您的应用程序是音乐商店吗?也许您的模型对象将是艺术家,专辑和歌曲。您的应用程序是组织结构图浏览器吗?也许您的模型对象将是经理和员工。这些模型对象与任何形式的视觉渲染都不相关,它们甚至与您要放入其中的应用程序也没有直接关系-模型对象作为代表某种类型的对象家族应该完全有意义域。模型层通常还包括诸如服务访问器之类的东西。

这将我们带到Viewmodels。这些是什么?它们是为GUI应用程序建模对象,表示它们提供了视图可使用的数据和功能。它们定义了正在构建的实际应用程序的结构和行为。对于模型对象,域是您选择的任何域(音乐商店,组织结构图浏览器等),但是对于viewmodel,域是图形应用程序。您的视图模型将封装应用程序所做的所有行为和数据。它们将对象和列表作为属性公开,以及诸如Commands之类的东西。命令只是包装在携带该对象的对象中的一种行为(最简单的方法调用)-这个想法很重要,因为视图是由数据绑定驱动的,该绑定将视觉控件附加到对象上。在MVVM中,您不会为按钮提供Click处理程序方法,

对我来说,最令人困惑的地方如下:

  • 即使视图模型是图形应用程序的模型,它们也不直接引用或使用视觉概念。例如,您不希望在ViewModels中引用Windows控件-这些东西都放在视图中。ViewModel只是向控件或将绑定到它们的其他对象公开数据和行为。例如-您是否有一个带有ListBox的视图?您的视图模型几乎肯定会包含其中的某种集合。您的视图有按钮吗?您的视图模型几乎肯定会包含一些命令。
  • 有几种对象可以视为“视图模型”。最简单的一种视图模型是直接以1:1关系表示控件或屏幕的视图模型,例如“屏幕XYZ具有一个文本框,一个列表框和三个按钮,因此,视图模型需要一个字符串,一个集合,和三个命令。” 适合视图模型层的另一种对象是模型对象的包装,该模型对象赋予其行为并使其在视图中更有用-在这里,您可以了解“厚”和“薄”视图模型层的概念。“薄”视图模型层是一组视图模型,这些模型将模型对象直接暴露给视图,这意味着视图最终直接绑定到模型对象的属性。这可以用于简单的只读视图,但是,如果您想让每个对象都有行为,该怎么办?您不希望在模型中使用该模型,因为该模型与应用程序无关,而仅与您的域相关。您可以将其放在包装模型对象的对象中,并提供更易于绑定的数据和行为。这个包装对象也被认为是一个视图模型,使它们成为一个“较厚”的视图模型层,在该层中,视图永远不会直接绑定到模型类上的任何内容。集合将包含包装模型的视图模型,而不仅仅是包含模型本身。您可以将其放在包装模型对象的对象中,并提供更易于绑定的数据和行为。这个包装对象也被认为是一个视图模型,使它们成为一个“较厚”的视图模型层,在该层中,视图永远不会直接绑定到模型类上的任何内容。集合将包含包装模型的视图模型,而不仅仅是包含模型本身。您可以将其放在包装模型对象的对象中,并提供更易于绑定的数据和行为。这个包装对象也被认为是一个视图模型,使它们成为一个“较厚”的视图模型层,在该层中,视图永远不会直接绑定到模型类上的任何内容。集合将包含包装模型的视图模型,而不仅仅是包含模型本身。

难题变得更深了-有很多习惯用法可以使ValueVM保持正常运行,例如ValueConverters,而当您开始考虑诸如可混合性,测试以及如何在应用程序中传递数据并确保每个视图模型都可以访问所需的行为(这是依赖注入的来源),但希望以上内容是一个好的开始。关键是将您的视觉效果,您的领域以及实际应用程序的结构和行为视为三件不同的事情。


3
+1-我到这里结束了,因为我对某些示例代码中遇到的“包装” ViewModel感到困惑。感谢您为我解决问题:-)
Riegardt Steyn

1
好的答案-希望我能+10。
Nick Hodges 2013年

1
@nlawalker太棒了!上面的双重注释使我很困惑。许多文章和博客仅讲述了MVVM的“关键特性”,但是当您尝试使用它时,事情开始变得非常复杂!例如“如何浏览这些视图?” “设计ViewModels时合适的粒度是多少?” “一个视图必须具有匹配的ViewModel或一个ViewModel可以在不同的视图中重用吗?”您对由“ Slim VM”和“ Thick VM”组成的ViewModel的说明确实很有意义!我正在尝试,它工作得很好!!)
Claw

@nlawalker谢谢!还有另一个问题:我有treeView并制作了TreeViewViewModel。因此,如果我在ViewModel上创建类似:ExpandTree()的方法。正确的方法吗?
user2545071 2015年

哇,这是一篇很棒的文章,做得很好@nlawalker
Vivek Shukla

25

使用这篇非常有用的文章作为源,这里是ViewViewModelModel的摘要。


视图:

  • 视图是可视元素,例如窗口,页面,用户控件或数据模板。该视图定义了视图中包含的控件以及它们的视觉布局和样式。

  • 视图通过其DataContext属性引用视图模型。视图中的控件是绑定到视图模型公开的属性和命令的数据。

  • 视图可以自定义视图和视图模型之间的数据绑定行为。例如,视图可以使用值转换器来格式化要在UI中显示的数据,也可以使用验证规则向用户提供其他输入数据验证。

  • 该视图定义并处理UI视觉行为,例如动画或过渡,这些动画或过渡可能是由于视图模型中的状态更改或通过用户与UI的交互而触发的。

  • 视图的背后代码可能会定义UI逻辑,以实现难以用XAML表示或要求直接引用视图中定义的特定UI控件的视觉行为。

注意:
由于视图模型不应该明确了解视图中的特定视觉元素,因此以编程方式操作视图中的视觉元素的代码应驻留在视图的代码背后或封装在行为中。


查看模型:

  • 视图模型是非可视类,并且不派生自任何WPF或Silverlight基类。它封装了支持应用程序中的用例或用户任务所需的表示逻辑。视图模型可以独立于视图和模型进行测试。

  • 视图模型通常不直接引用视图。它实现了视图可以数据绑定到的属性和命令。它通过INotifyPropertyChangedINotifyCollectionChanged接口通过更改通知事件将状态更改通知给视图。

  • 视图模型协调视图与模型的交互。它可以转换或操纵数据,以便视图可以轻松使用它,并且可以实现模型上可能不存在的其他属性。它还可以通过IDataErrorInfoINotifyDataErrorInfo接口实现数据验证。

  • 视图模型可以定义视图可以在视觉上呈现给用户的逻辑状态。

注意:
对应用程序的逻辑行为重要的任何内容都应纳入视图模型。用于通过数据绑定检索或操作将在视图中显示的数据项的代码应驻留在视图模型中。


模型:

  • 模型类是非可视类,它们封装了应用程序的数据和业务逻辑。他们负责管理应用程序的数据,并通过封装所需的业务规则和数据验证逻辑来​​确保其一致性和有效性。

  • 模型类不直接引用视图或视图模型类,也不依赖于它们的实现方式。

  • 模型类通常通过INotifyPropertyChangedINotifyCollectionChanged接口提供属性和集合更改通知事件。这使它们易于在视图中进行数据绑定。代表对象集合的模型类通常从ObservableCollection<T>该类派生。

  • 模型类通常通过IDataErrorInfoINotifyDataErrorInfo接口提供数据验证和错误报告。

  • 模型类通常与封装数据访问和缓存的服务或存储库结合使用。


17

正如我在MVVM上的系列文章中所想到的那样,我将其写成“普通英语” 。特别是,此图可能是最简单,简短的说明。

就是说,基本上,“模型”是您的数据或业务规则。它真的不应该知道如何或在哪里使用它,尤其是不知道要使用哪种技术。“模型”是应用程序的核心要素-无需担心应用程序是否为WPF,Silverlight,Windows Forms,ASP.NET等-它只是纯形式的“自身”。

“视图”是完全与技术相关的部分。在MVVM中,理想情况下,View应该接近100%XAML,因为这样做可以极大地提高灵活性。

但是,必须有某种东西可以将模型中的信息转换为某种形式,以供手头的技术使用-这正是ViewModel发挥作用的地方。例如,这通常将模型类“包装”到用于特定数据的“ ViewModel”中,这些特定数据包括命令(用于运行逻辑),实现INotifyPropertyChanged(用于数据绑定支持)等。就是这样-正是构成模型的桥梁可用的视图。


好,谢谢。我认为Model是对象,而ViewModel是处理对象的方法,这样视图就可以理解Model的“对象”。但是我被告知这是错误的,ViewModel本身也是对象。我想这真是让我感到困惑。
RKM

@Rosie:我建议阅读我引用的系列文章(或至少浏览一下)。我之所以专门写它,是因为关于MVVM的文章很少(几乎没有)还没有假定您了解MVC或MVP等。这实际上是“逐步”过渡;)
Reed Copsey

意识到这有点僵尸线程。您的图表显示VM包含“特定于应用程序的状态和逻辑”(我的观点)。这是否表明您认为VM可以/应该包含数据质量检查逻辑?相关的RssWpfMVVM.csproj在其两个视图模型中似乎没有任何明显的QA。
鲁芬,2015年


0

构建一个在基础模型上呈现一致外观的ViewModel可能比看起来要复杂得多。这一篇关于构建视图模型对象演示如何构建一个视图模型,并说明了一些你可能会遇到的问题-什么样子合理的解决方案。当我阅读它时,缺少有关处理集合的部分,但是仍然有一些有趣的观点。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.