在MVVM应ViewModel或模型实现INotifyPropertyChanged?
我已经通过的大多数MVVM示例都使模型实现了INotifyPropertyChanged,但是在Josh Smith的CommandSink示例中 ,ViewModel实现了INotifyPropertyChanged 。
我仍然认知地把MVVM概念放在一起,所以我不知道是否:
- 您必须将INotifyPropertyChanged放在ViewModel中才能使CommandSink工作
- 这只是一个规范的畸变,并不重要
- 你应该总是让模型实现INotifyPropertyChanged,这只是一个错误,如果这是从代码示例开发到应用程序将被纠正
MVVM项目上的其他人的经验是什么?
我会说完全相反,我总是把我的INotifyPropertyChanged
放在我的ViewModel上 – 你真的不想用像INotifyPropertyChanged
这样的WPF特有function来污染你的模型,这些东西应该放在ViewModel中。
我相信其他人会不同意,但这是我工作的方式。
我强烈反对模型不应该实现INotifyPropertyChanged
的概念。 这个界面不是UI特定的! 它只是通知一个变化。 事实上,WPF大量使用它来识别更改,但并不意味着它是一个UI界面。 我会比较下面的评论“轮胎是汽车配件”。 当然,但是自行车,公共汽车等也使用它。 总之,不要把这个接口作为一个UI的东西。
话虽如此,在提供通知的模式中,我并不需要这样做。 事实上,作为一个经验法则,模型不应该实现这个接口,除非有必要。 在大多数情况下,没有服务器数据被推送到客户端应用程序,该模型可能是陈旧的。 但是如果听金融市场数据,那么我不明白为什么模型不能实现这个接口。 举个例子,如果我有一个非UI逻辑,如服务,如果收到出价或要价的价值,它会发出警报 – 通过电子邮件 – 或下订单,那么这可能是一个可能的干净的解决scheme。
但是,有不同的方法来实现,但我总是主张简单,避免冗余。
什么是更好的? 定义集合或属性上的事件在视图模型上发生变化并将其传播到模型或使视图本质上更新模型(通过视图模型)?
底线,当你看到有人声称“你不能做这个或那个”这是作为标志,他们不知道他们在说什么。
这真的取决于你的情况,实际上MVVM是一个有很多问题的框架,我还没有看到MVVM的通用实现。
我希望我有更多的时间来解释MVVM的许多风格和解决常见问题的一些解决scheme – 大部分是由其他开发人员提供的 – 但我想我将不得不再做一次。
在MV-VM中,ViewModel总是(Model not always)实现INotifyPropertyChanged
从http://blogs.msdn.com/llobo/archive/2009/05/01/download-mv-vm-project-template-toolkit.aspx查看MV-VM项目模板/工具包。; 它使用DelegateCommand
进行命令,它应该是MV-VM项目的一个很好的开始模板。
我认为MVVM命名非常糟糕,调用ViewModel ViewModel会导致许多人错过devise良好的架构的一个重要特性,即无论谁试图触摸它,都可以控制数据的DataController。
如果将View-Model看作更多的DataController并实现一个体系结构,其中DataController是唯一触及数据的项目,那么您将永远不会直接触摸数据,但始终使用DataController。 DataController对于用户界面非常有用,但不一定仅用于UI。 它是为业务层,UI层等…
DataModel -------- DataController ------ View / Business --------/
你最终会有这样的模型。 即使业务应该只使用ViewModel来触摸数据。 那么你的难题就消失了。
这取决于你如何实现你的模型。 我的公司使用类似于Lhotka的CSLA对象的业务对象,并在整个业务模型中广泛使用INotifyPropertyChanged。
我们的validation引擎在很大程度上依赖于通过这种机制通知属性改变,并且工作得很好。 显然,如果您正在使用除业务对象之外的其他实现,而这些实现的更改通知对于操作来说并不重要,则可能有其他方法来检测业务模型中的更改。
我们还有视图模型,它根据需要传播来自模型的更改,但视图模型本身正在监听基础模型更改。
我会说你的ViewModel。 这不是模型的一部分,因为模型是UI不可知的。 该模型应该是“除了业务不可知论者之外的一切”
但有时(如在此演示文稿中的链接文本 )模型是服务,它为应用程序提供一些在线数据,然后您需要充实通知新数据到达或数据已使用事件更改…
如果你想坚持MV-VM,我的答案是非常清楚的。
请参阅: http : //msdn.microsoft.com/en-us/library/gg405484(v=PandP.40).aspx
在MVVM模式中,视图封装了UI和任何UI逻辑,视图模型封装了表示逻辑和状态,模型封装了业务逻辑和数据。
“视图通过数据绑定,命令和更改通知事件与视图模型交互,视图模型查询,观察和协调模型的更新,转换,validation和聚合数据,以便在视图中显示。
我认为这一切都取决于用例。
当你有一个简单的模型负载属性,你可以让它实现INPC。 简而言之,我的意思是这个模型看起来更像一个POCO 。
如果你的模型更复杂,并且生活在一个交互模型领域 – 模型引用模型,订阅其他模型的事件 – 将模型事件实现为INPC是一个噩梦。
把自己置于某个模型实体的位置,这个模型实体必须与其他模型合作。 你有各种事件订阅。 所有这些都是作为INPC实施的。 想象一下你拥有的事件处理程序。 一个巨大的if-clause和/或开关clausses级联。
INPC的另一个问题。 您应该devise您的应用程序依靠抽象,而不是实现。 这通常是使用接口完成的。
让我们来看看同一个抽象的两种不同的实现:
public class ConnectionStateChangedEventArgs : EventArgs { public bool IsConnected {get;set;} } interface IConnectionManagerINPC : INotifyPropertyChanged { string Name {get;} int ConnectionsLimit {get;} /* A few more properties */ bool IsConnected {get;} } interface IConnectionManager { string Name {get;} int ConnectionsLimit {get;} /* A few more properties */ event EventHandler<ConnectionStateChangedEventArgs> ConnectionStateChanged; bool IsConnected {get;} }
现在看看他们两个。 IConnectionManagerINPC告诉你什么? 它的一些属性可能会改变。 你不知道他们中的哪一个。 事实上,devise是只有IsConnected发生变化,因为其余部分是只读的。
相反,IConnectionManager的意图是明确的:“我可以告诉你,我的IsConnected属性的值可能会改变”。
只需在视图模型中使用INotifyPropertyChange
而不是在Model中,
该模型通常使用IDataErrorInfo
来处理validation错误,所以只要保留在您的ViewModel中,并且您正好在MVVM之路上。
假设你的视图中对象的引用改变了。 你将如何通知所有属性进行更新,以显示正确的值? 在您的视图中调用OnPropertyChanged
所有对象的属性是垃圾到我的观点。
所以我所做的就是让对象本身在属性值发生变化时通知任何人,并且在我看来,我使用了Object.Property1
, Object.Property2
和on之类的绑定。 这样,如果我只是想改变当前维护在我的视图中的对象,我只是做OnPropertyChanged("Object")
。
为了避免加载对象期间的数百个通知,我有一个私人的布尔指标,我把它设置为true在加载过程中,从对象的OnPropertyChanged
检查,什么也不做。
我在模型中使用INotifyPropertyChange
接口。 实际上,模型属性的改变只能由UI或外部客户端触发。
我注意到了几个优点和缺点:
优点
Notifier是商业模式
- 按照域驱动,这是正确的。 它应该决定什么时候提出,什么时候不。
缺点
该模型有属性(数量,费率,佣金,totalfrieght)。 总费用计算使用数量,费率,佣金变化。
-
在从db加载值时,总计计算被称为3次(数量,费率,佣金)。 应该是一次。
-
如果在业务层中分配了费率,数量,则再次通知者被调用。
-
应该有一个选项来禁用这个,可能在基类中。 但是,开发人员可能忘了这样做。
通常ViewModel将实现INotifyPropertyChanged
。 模型可以是任何东西(XML文件,数据库甚至对象)。 模型用于将数据提供给传播到视图的视图模型。
看这里
我同意Paulo的回答,在Models中实现INotifyPropertyChanged
是完全可以接受的,甚至被微软build议 –
通常,该模型实现了便于绑定到视图的function。 这通常意味着它通过
INotifyPropertyChanged
和INotifyCollectionChanged
接口支持属性和集合更改通知。 表示对象集合的模型类通常来自ObservableCollection<T>
类,它提供了INotifyCollectionChanged
接口的实现。
虽然由您来决定是否需要这种types的实现,但请记住 –
如果你的模型类没有实现所需的接口呢?
有时您需要使用不实现
INotifyPropertyChanged
,INotifyCollectionChanged
,IDataErrorInfo
或INotifyDataErrorInfo
接口的模型对象。 在这些情况下,视图模型可能需要包装模型对象并将所需的属性暴露给视图。 这些属性的值将由模型对象直接提供。 视图模型将为其公开的属性实现所需的接口,以便视图可以轻松地将数据绑定到它们。
取自 – http://msdn.microsoft.com/zh-cn/library/gg405484(PandP.40).aspx
我曾经在一些项目中工作过,在我们的模型中没有实现INotifyPropertyChanged
,因此我们遇到了很多问题。 在虚拟机中需要不必要的属性重复,同时我们必须在将它们传递给BL / DL之前更新底层对象(具有更新的值)。
如果您需要处理收集模型对象(比如可编辑的网格或列表)或复杂的模型,您将面临特别的问题; 模型对象将不会自动更新,您将不得不pipe理虚拟机中的所有内容。
最初在另一个类似的问题上回答,因为它包含imp。 从这个线程中缺less的细节 –
恕我直言,我认为视图模型实现INotifyPropertyChange
和模型可以使用不同的“水平”的通知。
例如,对于某些文档服务和文档对象,您有一个viewCodele侦听的documentChanged事件清除并重build视图。 在编辑viewmodel中,您有一个propertychange文件的属性来支持视图。 如果服务在保存文件上做了很多事情(更新更改date,最后一个用户等等),那么您容易得到Ipropertychanged事件的重载,只是一个documentchanged已经足够了。
但是,如果你在你的模型中使用INotifyPropertyChange
,我认为在你的viewmodel中传递它是一个好习惯,而不是直接在你的视图中订阅它。 在这种情况下,当模型中的事件发生变化时,您只需更改视图模型,视图保持不变。