Kent写了一篇关于这个话题的有趣博客:视图模型:POCO与DependencyObject。
简短总结:
我更喜欢POCO方法。可以在此处找到实现INotifyPropertyChanged接口的PresentationModel(又名ViewModel)的基类:http://compositeextensions.codeplex.com
选择完全基于您的业务逻辑和UI抽象级别。如果你不想要一个很好的分离,那么DP就适合你。
DependencyProperties主要适用于VisualElements级别,因此如果我们为每个业务需求创建大量的DP,则不是一个好主意。此外,DP的成本比INotifyPropertyChanged更高。当您设计WPF / Silverlight时,请尝试完全分离UI和ViewModel,以便在任何时间点都可以更改布局和UI控件(基于主题和样式)。
也可以参考这篇文章 - https://stackoverflow.com/questions/275098/what-applications-could-i-study-to-understand-datamodel-view-viewmodel。该链接包含许多与Model-View-ViewModel模式相关的参考资料,非常与本文讨论相关。
就表达能力而言,我非常喜欢使用依赖属性,并对使用 INotifyPropertyChanged
感到不满。除了 string
属性名称和由于事件订阅导致的可能的内存泄漏之外,INotifyPropertyChanged
是一个更为明确的机制。
依赖属性使用易于理解的静态元数据来暗示“当此时,执行那个”的关系。这是一种声明式的方法,使它在优雅方面得到了我的支持。
[CallerMemberName]
还有一些有趣的事情可以做。 - Bryan Watts依赖属性旨在支持UI元素的绑定(作为目标),而不是数据绑定的源。这就是INotifyProperty的作用所在。从纯粹的角度来看,您不应该在ViewModels上使用DP。
“为了成为绑定的源,属性不需要是依赖属性;您可以使用任何CLR属性作为绑定源。但是,为了成为绑定的目标,属性必须是依赖属性。对于单向或双向绑定,源属性必须支持传播到绑定系统并因此传播到目标的更改通知。对于自定义CLR绑定源,这意味着该属性必须支持INotifyPropertyChanged。集合应支持INotifyCollectionChanged。”
所有依赖对象都无法序列化(这可能会阻碍ViewModels和DTO(POCO)的使用)。
Silverlight中的DP与WPF中有所不同。
http://msdn.microsoft.com/zh-cn/library/cc221408(v=VS.95).aspx
http://msdn.microsoft.com/zh-cn/library/cc903933(VS.95).aspx
INotifyPropertyChanged
被使用时,还能在属性的getter和setter代码中增加更多的逻辑。
DependencyProperty
示例:
public static DependencyProperty NameProperty = DependencyProperty.Register( "Name", typeof( String), typeof( Customer ) );
public String Name
{
set { SetValue( NameProperty, value ); }
get { return ( String ) GetValue( NameProperty ); }
}
在你的getter和setter中,你只能简单地分别调用SetValue和GetValue,因为在框架的其他部分中getter/setter不会被调用,而是直接调用SetValue、GetValue,因此你的属性逻辑不能可靠地执行。
使用INotifyPropertyChanged,定义一个事件:public event PropertyChangedEventHandler PropertyChanged;
然后在您的代码中任何位置编写逻辑,接着调用:
// ...
// Something cool...
// ...
if( this.PropertyChanged != null )
{
PropertyChanged( this, new PropertyChangedEventArgs( "Name" ) );
}
// More cool stuff that will reliably happen...
这可以在 getter/setter 或任何其他地方使用。
最近我也必须考虑这个决定。
我发现INotifyPropertyChanged机制更适合我的需求,因为它允许我将GUI与现有的业务逻辑框架连接起来,而不会重复状态。我使用的框架具有自己的观察者模式,很容易将一级通知转发到下一级。我只需要一个类来实现我的业务逻辑框架中的观察者接口和INotifyPropertyChanged接口。
使用DP,您无法自定义存储状态的后端。我必须让.NET缓存我要绑定的每个状态项的副本。这似乎是一种不必要的开销——我的状态又大又复杂。
因此,我发现INotifyPropertyChanged更适用于从业务逻辑到GUI公开属性。
尽管如此,在我需要自定义GUI小部件来公开属性并且希望更改该属性以影响其他GUI小部件时,DP被证明是简单的解决方案。
因此,在那里我发现DP对于GUI到GUI通知非常有用。
将ViewModel的依赖项提供给WPF真的是一个好主意吗?
.NET 4.0将拥有System.Xaml.dll,因此您不必依赖任意框架来利用它。请参阅Rob Relyea关于他的PDC会话的帖子。
我的看法
XAML是描述对象的语言,而WPF是一个框架,其描述的对象是UI元素。
它们的关系类似于C#,一种描述逻辑的语言和.NET,一个实现特定类型逻辑的框架。
XAML的目的是声明性对象图。W*F技术非常适合这种范式,但XAML独立于它们存在。
XAML和整个依赖系统作为WF和WPF的单独堆栈实现,可能是为了利用不同团队的经验而不创建依赖(无意冒犯)它们之间。
依赖属性是自定义控件创建的粘合剂。如果您想在XAML设计时使用智能感知来显示属性窗口中的属性,则必须使用依赖属性。 INPC永远不会在设计时显示属性窗口中的属性。
我认为在绑定中,DependencyProperty和INotifyPropertyChanged用于两个不同的目的:第一个是使属性成为绑定的目标并从另一个属性接收输入(使用{Binding ...}设置属性),而最后一个则是当您希望属性的值被用作绑定的源时使用(在绑定路径表达式中使用名称)。因此,选择仅仅是技术上的。
INotifyPropertyChanged
接口的 .NET 4.5 方法。 - Daniel Little