当在一个模型-视图-视图模型架构的WPF应用程序中实现ViewModel时,似乎有两个主要的选择:如何使它可数据化。我已经看到实现使用DependencyProperty属性的视图要绑定,我已经看到ViewModel实现INotifyPropertyChanged代替。

我的问题是,什么时候我应该更喜欢其中一个?有什么性能差异吗?把ViewModel依赖项交给WPF真的是个好主意吗?在做设计决定时,我还需要考虑什么?


当前回答

我认为DependencyProperty和INotifyPropertyChanged在绑定中用于两种不同的事情:第一个用于使一个属性成为绑定的目标并接收来自另一个属性的输入(使用{Binding…}来设置属性),当你想要一个属性的值被用作绑定的源(绑定路径表达式中的名称)时,最后一个。 所以选择仅仅是技术上的。

其他回答

最近我也不得不考虑这个决定。

我发现INotifyPropertyChanged机制更适合我的需求,因为它允许我将GUI粘到现有的业务逻辑框架上,而不需要复制状态。我使用的框架有自己的观察者模式,很容易将一个级别的通知转发到下一个级别。我有一个简单的类,它实现了来自业务逻辑框架的观察者接口和INotifyPropertyChanged接口。

使用DP,您不能自己定义存储状态的后端。我将不得不让。net缓存我所绑定的每个状态项的副本。这似乎是一个不必要的开销-我的状态是大而复杂的。

因此,在这里我发现INotifyPropertyChanged更适合将属性从业务逻辑公开到GUI。

也就是说,我需要一个自定义GUI小部件来公开一个属性,并对该属性进行更改以影响其他GUI小部件DP证明了简单的解决方案。

所以我发现DP对于GUI到GUI的通知很有用。

依赖属性旨在支持在UI元素上绑定(作为目标),而不是作为数据绑定的源,这就是INotifyProperty的作用。从纯粹的角度来看,你不应该在ViewModels上使用DP。

"In order to be the source of a binding, a property does not need to be a dependency property; you can use any CLR property as a binding source. However, in order to be the target of a binding, the property must be a dependency property. For a one-way or two-way binding to be effective, the source property must support change notifications that propagate to the binding system and thus the target. For custom CLR binding sources, this means that the property must support INotifyPropertyChanged. Collections should support INotifyCollectionChanged."

所有依赖对象都不能被序列化(这可能会妨碍ViewModels和DTO (POCO)的使用。

与WPF相比,Silverlight中的DP有一些不同之处。

http://msdn.microsoft.com/en-us/library/cc221408 (v = VS.95) . aspx

http://msdn.microsoft.com/en-us/library/cc903933 (VS.95) . aspx

看起来依赖属性应该用在你创建的控件中,比如按钮。要在XAML中使用属性并使用所有WPF特性,这些属性必须具有依赖属性。

然而,你的ViewModel最好使用INotifyPropertyChanged。使用INotifyPropertyChanged可以让你在需要的时候拥有getter/setter逻辑。

我建议查看Josh Smith的基类版本,它已经实现了INotifyPropertyChanged:

http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/

我认为这是如何创建ViewModel的一个很好的例子。

Kent写了一篇关于这个主题的有趣博客:视图模型:POCOs与依赖对象。

简短的总结:

DependencyObjects没有被标记为 可序列化的 DependencyObject类重写并密封Equals()和 GetHashCode方法()方法 DependencyObject具有线程相关性——它只能被访问 就在那根线上 创建

我更喜欢POCO方法。PresentationModel(又名ViewModel)实现INotifyPropertyChanged接口的基类可以在这里找到:http://compositeextensions.codeplex.com

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, 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中,也可以在其他任何地方。