我已经学习了几个MVVM教程,发现可以两种方式实现。大多数使用ViewModel进行PropertyChanged(这也是我一直在做的),但我发现有一个教程是在Model中实现的。这两种方法都可行吗?如果可以,不同方法的优缺点是什么?
我已经学习了几个MVVM教程,发现可以两种方式实现。大多数使用ViewModel进行PropertyChanged(这也是我一直在做的),但我发现有一个教程是在Model中实现的。这两种方法都可行吗?如果可以,不同方法的优缺点是什么?
微软的模式和实践、MVVM的发明者John Gossman以及我都不同意所选择的答案。
通常,模型实现了使其易于与视图绑定的工具。这通常意味着它通过INotifyPropertyChanged和INotifyCollectionChanged接口支持属性和集合更改通知。表示对象集合的模型类通常派生自ObservableCollection类,该类提供了INotifyCollectionChanged接口的实现。
—— Microsoft Patterns and Practices:http://msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx#sec4
此时数据绑定就发挥作用了。在简单的例子中,视图直接向模型进行数据绑定。一些模型的部分仅通过单向数据绑定在视图中显示。可以将模型的其他部分直接双向绑定到数据控件上进行编辑。例如,模型中的布尔值可以数据绑定到复选框,或者字符串字段可以数据绑定到文本框。
—— MVVM的发明者John Gossman:http://blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx
我的文章:http://www.infoq.com/articles/View-Model-Definition
将“视图模型”仅包装一个模型并公开相同的属性列表是一种反模式。视图模型的工作是调用外部服务并公开这些服务返回的单个和多个模型。
原因:
这并不是说您永远不需要包装模型的视图模型。如果您的视图模型公开的属性与模型显着不同,并且不能仅使用IValueConverter进行覆盖,则包装视图模型是有意义的。
您可能需要包装视图模型的另一个原因是您的数据类由于某种原因不支持数据绑定。但即便如此,通常最好只是创建一个正常的可绑定模型并从原始数据类中复制数据。
当然,您的视图模型将具有特定于UI的属性,例如当前选择的集合中的哪个项目。
INotifyPropertyChanged
(INPC)接口用于Binding
。
因此,在平均情况下,您想在ViewModel
中实现它。
ViewModel
用于将Model
与您的View
解耦,因此无需在Model
中使用INPC,因为您不希望将Bindings
绑定到您的模型。
在大多数情况下,即使是较小的属性,您仍然有一个非常小的ViewModel
。
如果您想要一个坚实的MVVM
基础,您可能会使用某种MVVM Framework,如caliburn.micro。使用它将为您提供ViewModelBase
(或这里的NotifyPropertyChangedBase
),这样您就不必自己实现这些接口成员,并且可以直接使用NotifyOfPropertyChange(() => MyProperty)
,这样更容易、更少出错。
更新 由于似乎有很多Windows Forms开发人员,这里有一篇优秀的文章,可以更深入地了解MVVM的作用: MSDN Magazine on MVVM
我特别链接了有关数据模型的部分,这正是问题所在。
我完全同意Jonathan Allen的观点。
如果您在“View-Model”中没有要添加的内容(命令,影响演示等的特定于视图的属性),那么我肯定会在模型中实现INotifyPropertyChanged,并直接公开它(如果可以 - “模型”可能不是您的)。这样做不仅会重复很多样板代码,而且保持两者同步非常麻烦。
INotifyPropertyChanged不是一个特定于视图的接口,它只是像名称所示的那样 - 在属性更改时引发事件。 WinForms,WPF和Silverlight恰好支持它进行绑定 - 我肯定已经在非演示目的下使用它了!
ObservableCollection<Item>
比刻意创建一个 ItemViewModel
包装它、编写代码同步更改底层项目以触发适当的 PropertyChanged
事件、同步底层集合到 ViewModel 集合等要简单得多。在这种情况下,直接将模型绑定到视图会更简单-甚至是 Prism 指导文档所说的:http://msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx#sec4 - Charles MagerINotifyPropertyChanged
。这是因为未能这样做可能导致内存泄漏。所有被视图使用的类型都应该实现INotifyPropertyChanged接口(当然,如果它只有常量值则除外)。
你是否将模型(而不是视图模型)返回给视图?如果是,那么它应该实现INotifyPropertyChanged接口。
虽然我通常赞成模型实现INPC,但在复合视图模型中调用INPC的原因是它公开了可绑定到视图的推断属性。在我看来,由于INPC已经被嵌入到System.dll中,实现它的模型可能被认为是POCO。对于集合,基于模型的INPC有性能优势。在64位平台上,与ObservableCollection<Model>相比,包装器VM的字节大小会有8倍的乘数(加载SOS调试器扩展以获取实际大小)。