C# MVVM - 模型或视图模型中的 PropertyChanged?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/16864610/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
MVVM - PropertyChanged in Model or ViewModel?
提问by Jason D
I have gone through a few MVVM tutorials and I have seen this done both ways. Most use the ViewModel for PropertyChanged (which is what I have been doing), but I came across one that did this in the Model. Are both methods acceptable? If so, what are the benefits/drawbacks of the different methods?
我已经阅读了一些 MVVM 教程,我已经看到这两种方式都可以做到。大多数使用 ViewModel for PropertyChanged(这是我一直在做的),但我在模型中遇到了一个这样做的。这两种方法都可以接受吗?如果是这样,不同方法的优点/缺点是什么?
采纳答案by Mare Infinitus
The INotifyPropertyChanged(INPC) interface is used for Binding.
的INotifyPropertyChanged(INPC)接口用于Binding。
So, in the average case, you want to implement it in your ViewModel.
因此,在一般情况下,您希望在ViewModel.
The ViewModelis used to decouple the Modelfrom your View, so there is no need to have INPC in your Model, as you do not want Bindingsto your Model.
该ViewModel用于解耦Model从你的View,所以没有必要有INPC在你的Model,因为你不希望Bindings你的Model。
In most cases, even for smaller properties, you still have a very small ViewModel.
在大多数情况下,即使对于较小的属性,您仍然拥有非常小的ViewModel.
If you want a solid base for MVVM, you are probably going to use some kind of MVVM Framework like caliburn.micro. Using it will give you a ViewModelBase(or here NotifyPropertyChangedBase) so that you do not have to implement those interface members yourself and can just use NotifyOfPropertyChange(() => MyProperty), which is way easier and less error prone.
如果你想要一个坚实的基础MVVM,你可能会使用某种 MVVM 框架,比如caliburn.micro。使用它会给你一个ViewModelBase(或在这里NotifyPropertyChangedBase),这样你就不必自己实现这些接口成员,而可以使用NotifyOfPropertyChange(() => MyProperty),这更容易,更不容易出错。
UPDATEAs there seem to be many Windows Forms developers out there, here is an excellent article that will give deeper understanding of what MVVM is about: MSDN Magazine on MVVM
更新由于似乎有很多 Windows 窗体开发人员,这里有一篇出色的文章,可以让您更深入地了解 MVVM 的含义: MSDN Magazine on MVVM
I have linked especially the part about the datamodel, that the question is about.
我特别链接了有关数据模型的部分,即问题所在。
回答by Federico Berasategui
As a rule of thumb, any object that you will bind to (even if you don't need Two-Way binding and Property Change Notification), must implement INotifyPropertyChanged. This is because failing to do so May cause memory leaks
根据经验,您将绑定到的任何对象(即使您不需要双向绑定和属性更改通知),都必须实现INotifyPropertyChanged. 这是因为不这样做可能会导致内存泄漏
回答by lightbricko
INotifyPropertyChanged should be implemented by all the types that are consumed by the view (unless if it only has constant values of course).
INotifyPropertyChanged 应该由视图使用的所有类型实现(除非它当然只有常量值)。
Do you return models (not viewmodels) to a view? If yes, then it should implement INotifyPropertyChanged.
您是否将模型(而不是视图模型)返回到视图?如果是,那么它应该实现 INotifyPropertyChanged。
回答by Jonathan Allen
Microsoft's Patterns and Practices, the inventor of MVVM, and I all disagree with the chosen answer.
微软的 Patterns and Practices,MVVM 的发明者,我和我都不同意这个选择的答案。
Typically, the model implements the facilities that make it easy to bind to the view. This usually means it supports property and collection changed notification through the INotifyPropertyChanged and INotifyCollectionChanged interfaces. Models classes that represent collections of objects typically derive from the ObservableCollection class, which provides an implementation of the INotifyCollectionChanged interface.
通常,模型实现了易于绑定到视图的工具。这通常意味着它通过 INotifyPropertyChanged 和 INotifyCollectionChanged 接口支持属性和集合更改通知。表示对象集合的模型类通常从 ObservableCollection 类派生,该类提供 INotifyCollectionChanged 接口的实现。
-- Microsoft Patterns and Practices: http://msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx#sec4
-- Microsoft 模式和实践:http: //msdn.microsoft.com/en-us/library/gg405484%28v=pandp.40%29.aspx#sec4
At this point data binding comes into play. In simple examples, the View is data bound directly to the Model. Parts of the Model are simply displayed in the view by one-way data binding. Other parts of the model can be edited by directly binding controls two-way to the data. For example, a boolean in the Model can be data bound to a CheckBox, or a string field to a TextBox.
此时数据绑定开始发挥作用。在简单的例子中,视图是直接绑定到模型的数据。模型的一部分通过单向数据绑定简单地显示在视图中。模型的其他部分可以通过直接将控件双向绑定到数据来编辑。例如,模型中的布尔值可以是绑定到 CheckBox 的数据,或者绑定到 TextBox 的字符串字段。
-- John Gossman, inventor of MVVM: http://blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx
-- John Gossman,MVVM 的发明者:http: //blogs.msdn.com/b/johngossman/archive/2005/10/08/478683.aspx
My own article: http://www.infoq.com/articles/View-Model-Definition
我自己的文章:http: //www.infoq.com/articles/View-Model-Definition
It is an anti-pattern to have a "view-model" that just wraps a model and exposes the same list of properties. The view-model's job is to call external services and expose the individual and collections of models that those services return.
拥有一个只包装模型并公开相同属性列表的“视图模型”是一种反模式。视图模型的工作是调用外部服务并公开这些服务返回的单个模型和模型集合。
Reasons:
原因:
- If the model is updated directly, the view-model won't know to fire a property changed event. This causes the UI to go out of sync.
- This severely limits your options for sending messages between parent and child view-models.
- If the model has its own property changed notification, #1 and 2 aren't a problem. Instead, you have to worry about memory leaks if the wrapper VM goes out of scope but the model doesn't.
- If your models are complex, with lots of children objects, then you have to walk the entire tree and create a second object graph that shadows the first one. This can be quite tedious and error prone.
- Wrapped collections are particularly difficult to work with. Any time something (UI or backend) inserts or removes an item from a collection, the shadow collection needs to be updated to match. This kind of code is really hard to get right.
- 如果直接更新模型,视图模型将不知道触发属性更改事件。这会导致 UI 不同步。
- 这严重限制了您在父视图模型和子视图模型之间发送消息的选择。
- 如果模型有自己的属性更改通知,#1 和 2 不是问题。相反,如果包装器 VM 超出范围但模型没有超出范围,则您必须担心内存泄漏。
- 如果你的模型很复杂,有很多子对象,那么你必须遍历整个树并创建第二个对象图来遮蔽第一个。这可能非常乏味且容易出错。
- 包装好的集合特别难以处理。任何时候(UI 或后端)从集合中插入或删除项目,影子集合都需要更新以匹配。这种代码真的很难正确。
That isn't to say you will never need a view-model that wraps a model. If your view-model exposes properties that are significantly different from the model and can't just be papered over with a IValueConverter, then a wrapping view-model makes sense.
这并不是说您永远不需要包装模型的视图模型。如果您的视图模型公开与模型显着不同的属性并且不能仅用 IValueConverter 覆盖,那么包装视图模型是有意义的。
Another reason you may need a wrapping view-model is that your data classes don't support data binding for some reason. But even then, it is usually better to just create a normal, bindable model and copy the data from the original data classes.
您可能需要包装视图模型的另一个原因是您的数据类出于某种原因不支持数据绑定。但即便如此,通常最好只创建一个普通的、可绑定的模型并从原始数据类中复制数据。
And of course your view-model is going to have UI specific properties such as which item in a collection is currently selected.
当然,您的视图模型将具有特定于 UI 的属性,例如当前选择了集合中的哪个项目。
回答by Charles Mager
Would absolutely agree with Jonathan Allen.
绝对同意乔纳森·艾伦的观点。
If you have nothing to add to your 'View-Model' (Commands, view-specific properties that affect presentation etc.) then I would definitely implement INotifyPropertyChanged in the model and expose that directly (if you can - the 'model' may not be yours). Not only do you end up repeating a lot of boilerplate code, keeping the two in sync is an absolute pain.
如果您没有什么可添加到您的“视图模型”(命令、影响演示文稿的特定于视图的属性等),那么我肯定会在模型中实现 INotifyPropertyChanged 并直接公开它(如果可以的话 - “模型”可能不会成为你的)。您不仅最终会重复大量样板代码,而且保持两者同步绝对是一件痛苦的事情。
INotifyPropertyChanged isn't a view-specific interface, it only does exactly what the name suggests - raises an event when a property changes. WinForms, WPF and Silverlight just happen to support it for Binding - I've certainly used it in for non-presentational purposes!
INotifyPropertyChanged 不是特定于视图的接口,它只是按照名称所暗示的那样执行 - 在属性更改时引发事件。WinForms、WPF 和 Silverlight 恰好支持它用于绑定 - 我当然已经将它用于非演示目的!
回答by Rohit
While I'm generally in favor of a model implementing INPC the call for INPC in a composite view model is when it exposes inferred properties that are bindable to the view. IMO since INPC is baked into System.dll, a model implementing it may be considered POCO. For collections there is a performance benefit of model based INPC. On a 64 bit platform a wrapper VM would have an 8 factor multiplier on the byte size (load the SOS debugger extension for actual size) of ObservableCollection<ViewModel> compared to ObservableCollection<Model>.
虽然我通常支持实现 INPC 的模型,但在复合视图模型中对 INPC 的调用是当它公开可绑定到视图的推断属性时。IMO 因为 INPC 被烘焙到 System.dll 中,实现它的模型可能被认为是 POCO。对于集合,基于模型的 INPC 具有性能优势。在 64 位平台上,与 ObservableCollection<Model> 相比,包装器 VM 在 ObservableCollection<ViewModel> 的字节大小(加载 SOS 调试器扩展以获取实际大小)上将具有 8 倍的乘数。
回答by Rui Santos
The creator of MVVM, JohnGossman, states in thisblog article (mentioned by @Jonathan Allen) that:
MVVM 的创建者 JohnGossman 在这篇博客文章(@Jonathan Allen 提到)中指出:
In simple examples, the View is data bound directly to the Model. Parts of the Model are simply displayed in the view by one-way data binding. Other parts of the model can be edited by directly binding controls two-way to the data. For example, a boolean in the Model can be data bound to a CheckBox, or a string field to a TextBox.
In practice however, only a small subset of application UI can be data bound directly to the Model, especially if the Model is a pre-existing class or data schema over which the application developer has no control.
在简单的例子中,视图是直接绑定到模型的数据。模型的一部分通过单向数据绑定简单地显示在视图中。模型的其他部分可以通过直接将控件双向绑定到数据来编辑。例如,模型中的布尔值可以是绑定到 CheckBox 的数据,或者绑定到 TextBox 的字符串字段。
然而,在实践中,只有一小部分应用程序 UI 可以将数据直接绑定到模型,特别是如果模型是应用程序开发人员无法控制的预先存在的类或数据模式。
I prefer to follow practices that are still applicable when the app scales.
If "In practice [...], only a small subset of application UI can be data bound directly to the Model", this doesn't seem to be a good practice to follow as I don't plan to tackle only "simple cases" or "a small subset of application UI".
For "simple cases" I wouldn't even be using MVVM to begin with.
我更喜欢遵循在应用扩展时仍然适用的实践。如果“在实践中 [...],只有一小部分应用程序 UI 可以将数据直接绑定到模型”,这似乎不是一个很好的做法,因为我不打算只处理“简单的案例”或“应用程序 UI 的一个小子集”。
对于“简单情况”,我什至不会使用 MVVM 开始。

