在Model-View-ViewModel体系结构WPF应用程序中实现ViewModel时,似乎有两个主要选择来使它可数据绑定。我已经看到DependencyProperty
了将View绑定到的属性的实现,并且看到了ViewModel的实现INotifyPropertyChanged
。
我的问题是,什么时候我应该优先选择另一个?有性能差异吗?将ViewModel依赖项提供给WPF真的是一个好主意吗?做出设计决策时,我还需要考虑什么?
INotifyPropertyChanged
。
在Model-View-ViewModel体系结构WPF应用程序中实现ViewModel时,似乎有两个主要选择来使它可数据绑定。我已经看到DependencyProperty
了将View绑定到的属性的实现,并且看到了ViewModel的实现INotifyPropertyChanged
。
我的问题是,什么时候我应该优先选择另一个?有性能差异吗?将ViewModel依赖项提供给WPF真的是一个好主意吗?做出设计决策时,我还需要考虑什么?
INotifyPropertyChanged
。
Answers:
肯特(Kent)撰写了有关该主题的有趣博客:“ 视图模型:POCO与DependencyObjects”。
简短的摘要:
我更喜欢POCO方法。可以在以下位置找到实现INotifyPropertyChanged接口的PresentationModel(也称为ViewModel)的基类:http : //compositeextensions.codeplex.com
根据WPF性能指南,DependencyObjects的性能肯定比实现INotifyPropertyChanged的POCO更好:
该选择完全基于您的业务逻辑和UI抽象级别。如果您不希望分开,那么DP将为您工作。
DependencyProperties主要适用于VisualElements级别,因此如果我们为我们的每个业务需求创建大量的DP,将不是一个好主意。而且,DP的成本比INotifyPropertyChanged高。当您设计WPF / Silverlight时,请尝试将UI和ViewModel设计为完全分开,以便在任何时候我们都可以更改Layout和UI控件(基于主题和样式)
另请参阅此帖子-https: //stackoverflow.com/questions/275098/what-applications-could-i-study-to-understand-datamodel-view-viewmodel。该链接对Model-View-ViewModel模式有很多参考,与该讨论非常相关。
从表达的角度来看,我非常喜欢使用依赖属性,并且对的想法有所畏惧INotifyPropertyChanged
。除了string
属性名称和事件订阅可能导致的内存泄漏之外,这INotifyPropertyChanged
是一种更为明确的机制。
依赖项属性使用易于理解的静态元数据“在需要时执行此操作”。这是一种声明式方法,赢得了我的赞成。
[CallerMemberName]
。
INotifyPropertyChanged
当使用时,还使您能够在获取器和属性的设置器的代码中添加更多逻辑。
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,在框架的其他部分中b / c不会调用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或其他任何地方。
依赖项属性旨在支持在UI元素上进行绑定(作为目标),而不是作为数据绑定的源,这就是INotifyProperty的用处。从纯粹的角度来看,您不应在ViewModels上使用DP。
“要成为绑定的源,属性不必是依赖项属性;可以将任何CLR属性用作绑定源。但是,要成为绑定的目标,该属性必须是依赖属性:为了使单向或双向绑定有效,源属性必须支持传播到绑定系统并进而传播到目标的更改通知;对于自定义CLR绑定源,这意味着该属性必须支持INotifyPropertyChanged。集合应支持INotifyCollectionChanged。”
所有依赖项对象无法序列化(这可能会妨碍ViewModels和DTO(POCO)的使用)。
与WPF相比,Silverlight中的DP之间存在差异。
http://msdn.microsoft.com/zh-CN/library/cc221408(v=VS.95).aspx
http://msdn.microsoft.com/zh-CN/library/cc903933(VS.95).aspx
我最近也不得不考虑这个决定。
我发现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中使用属性并使用所有WPF功能,这些属性必须是“依赖项属性”。
但是,使用INotifyPropertyChanged最好使用ViewModel。如果需要,使用INotifyPropertyChanged将使您能够具有getter / setter逻辑。
我建议为已经实现INotifyPropertyChanged的ViewModel检出Josh Smith的基类版本:
http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/
我认为这是如何执行ViewModel的绝佳示例。
我认为DependencyProperty和INotifyPropertyChanged用于Binding中的两个不同事物:第一个用于使属性成为绑定的目标,并从另一个属性接收输入(使用{Binding ...}设置属性),最后一个当您希望将属性的值用作绑定源(绑定路径表达式中的名称)时。因此,选择仅仅是技术上的。
我更喜欢一种更直接的方法,该方法是我在Presentation Model中没有INotifyPropertyChanged的博客中发布的。使用数据绑定的替代方法,您可以直接绑定到CLR属性,而无需任何簿记代码。您只需在视图模型中编写普通的.NET代码,然后在您的数据模型更改时对其进行更新。
为什么偏爱DependencyObject
绑定只有一件事-绑定会更好。只需尝试使用ListBox
和的示例,TextBox
用INotifyPropertyChanged
属性vs.的数据填充列表,然后从中DependencyProperty
编辑当前项目即可TextBox
。