MVVM - Model或ViewModel中的PropertyChanged?

时间:2013-05-31 19:34:12

标签: c# mvvm

我已经完成了一些MVVM教程,我已经看到了两种方式。大多数人使用ViewModel for PropertyChanged(这是我一直在做的),但我遇到了一个在模型中做到这一点。两种方法都可以接受吗如果是这样,不同方法的好处/缺点是什么?

7 个答案:

答案 0 :(得分:30)

微软的模式和实践,MVVM的发明者,我都不同意所选择的答案。

  

通常,模型实现了可以轻松绑定到视图的工具。这通常意味着它通过INotifyPropertyChanged和INotifyCollectionChanged接口支持属性和集合更改通知。表示对象集合的模型类通常派生自ObservableCollection类,该类提供INotifyCollectionChanged接口的实现。

- Microsoft模式和实践:http://msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx#sec4

  

此时数据绑定发挥作用。在简单示例中,View是直接绑定到Model的数据。模型的各个部分通过单向数据绑定简单地显示在视图中。可以通过直接将控件双向绑定到数据来编辑模型的其他部分。例如,Model中的布尔值可以是绑定到CheckBox的数据,也可以是绑定到TextBox的字符串字段。

- MVVM的发明者John Gossman:http://blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx

我自己的文章:http://www.infoq.com/articles/View-Model-Definition


具有“视图模型”的反模式只是包装模型并公开相同的属性列表。视图模型的工作是调用外部服务并公开这些服务返回的个体和模型集合。

原因:

  1. 如果直接更新模型,则视图模型将不知道触发属性更改事件。这会导致UI不同步。
  2. 这严重限制了您在父视图模型和子视图模型之间发送消息的选项。
  3. 如果模型有自己的属性更改通知,则#1和2不是问题。相反,如果包装器VM超出范围但模型没有,则必须担心内存泄漏。
  4. 如果您的模型很复杂,有很多子对象,那么您必须遍历整个树并创建第二个对象图,它会遮蔽第一个对象图。这可能非常繁琐且容易出错。
  5. 包装的收藏品特别难以使用。任何时候(UI或后端)从集合中插入或删除项目,都需要更新影子集合以匹配。这种代码很难做对。
  6. 这并不是说你永远不需要一个包装模型的视图模型。如果您的视图模型公开了与模型明显不同的属性,并且不能仅使用IValueConverter进行包装,那么包装视图模型是有意义的。

    您可能需要包装视图模型的另一个原因是您的数据类由于某种原因不支持数据绑定。但即便如此,通常最好只创建一个普通的可绑定模型并从原始数据类中复制数据。

    当然,您的视图模型将具有UI特定属性,例如当前选择了集合中的哪个项目。

答案 1 :(得分:16)

INotifyPropertyChanged(INPC)界面用于Binding

因此,在一般情况下,您希望在ViewModel

中实施它

ViewModel用于将ModelView分离,因此您无需在Model中使用INPC,因为您不希望Bindings 1}}到Model

在大多数情况下,即使是较小的属性,您仍然只有非常小的ViewModel

如果你想为MVVM建立一个坚实的基础,你可能会使用某种MVVM框架,如caliburn.micro。使用它将为您提供ViewModelBase(或此处NotifyPropertyChangedBase),这样您就不必自己实现这些界面成员,只需使用NotifyOfPropertyChange(() => MyProperty),这样更容易,更不容易出错

<强>更新 由于似乎有许多Windows窗体开发人员,这里是一个很好的 这篇文章将更深入地了解MVVM的内容: MSDN Magazine on MVVM

我特别关注了关于数据模型的部分,问题是关于。

答案 2 :(得分:4)

绝对赞同乔纳森·艾伦。

如果你没有任何东西可以添加到你的'View-Model'(命令,特定于视图的属性,影响演示等),那么我肯定会在模型中实现INotifyPropertyChanged并直接公开(如果可以的话 - '模型'可能不是你的)。你最终不仅重复了很多样板代码,保持两者同步是一种绝对的痛苦。

INotifyPropertyChanged不是特定于视图的界面,它只是完全按照名称建议 - 在属性更改时引发事件。 WinForms,WPF和Silverlight恰好支持它进行绑定 - 我当然将其用于非表示目的!

答案 3 :(得分:1)

根据经验,您要绑定的任何对象(即使您不需要双向绑定和属性更改通知)也必须实现INotifyPropertyChanged。这是因为没有这样做May cause memory leaks

答案 4 :(得分:1)

INotifyPropertyChanged应该由视图使用的所有类型实现(除非它当然只有常量值)。

您是否将模型(不是视图模型)返回到视图?如果是,那么它应该实现INotifyPropertyChanged。

答案 5 :(得分:1)

虽然我一般赞成实现INPC的模型,但在复合视图模型中调用INPC时,它会公开可绑定到视图的推断属性。 IMO因为INPC被编入System.dll,实现它的模型可能被认为是POCO。对于集合,基于模型的INPC具有性能优势。在64位平台上,包装器VM将在ObservableCollection&lt; ViewModel&gt;的字节大小(加载实际大小的SOS调试器扩展)上具有8因子乘数。与ObservableCollection&lt; Model&gt;相比。

答案 6 :(得分:1)

MVVM的创建者JohnGossman在this博客文章(@Jonathan Allen提到)中指出:

  

在简单的示例中,View是直接绑定到Model的数据。   模型的各个部分仅通过单向数据显示在视图中   捆绑。可以通过直接绑定来编辑模型的其他部分   控制双向数据。例如,Model中的布尔值可以   是绑定到CheckBox的数据,或字符串字段绑定到TextBox。

     

但实际上,只有一小部分应用程序UI可以是数据   直接绑定到模型,特别是如果模型是预先存在的   应用程序开发人员没有的类或数据模式   控制。   

我更愿意遵循应用扩展时仍然适用的做法。 如果“在实践中[...],只有一小部分应用程序UI可以直接绑定到模型”,这似乎不是一个好的做法,因为我不打算只解决“简单”案例“或”应用程序UI的一小部分“ 对于“简单案例”,我甚至不会使用MVVM开始。