368

在 Model-View-ViewModel 架构 WPF 应用程序中实现 ViewModel 时,似乎有两个主要选择如何使其可数据绑定。我已经看到了使用DependencyPropertyView 将要绑定的属性的实现,并且我看到了 ViewModel 的实现INotifyPropertyChanged

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

4

14 回答 14

221

Kent 写了一篇关于这个主题的有趣博客:View Models: POCOs vs DependencyObjects

简短的摘要:

  1. DependencyObjects 未标记为可序列化
  2. DependencyObject 类覆盖并封装了 Equals() 和 GetHashCode() 方法
  3. DependencyObject 具有线程亲和性——它只能在创建它的线程上访问

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

于 2009-04-23T19:15:39.263 回答
41

根据 WPF 性能指南,DependencyObjects 的性能肯定优于实现 INotifyPropertyChanged 的​​ POCO:

http://msdn.microsoft.com/en-us/library/bb613546.aspx

于 2010-11-03T16:45:21.567 回答
29

选择完全基于您的业务逻辑和 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 模式的参考,这与本次讨论非常相关。

于 2008-11-14T22:22:24.997 回答
20

从表现力的角度来看,我非常喜欢使用依赖属性并且一想到INotifyPropertyChanged. 除了string属性名称和由于事件订阅可能导致的内存泄漏之外,INotifyPropertyChanged还有一种更明确的机制。

依赖属性意味着使用易于理解的静态元数据“当这个做那个”。这是一种声明式的方法,让我对优雅投了赞成票。

于 2008-11-15T23:35:40.463 回答
17

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

“要成为绑定的源,属性不必是依赖属性;您可以使用任何 CLR 属性作为绑定源。但是,要成为绑定的目标,该属性必须是依赖属性。要使单向或双向绑定有效,源属性必须支持传播到绑定系统和目标的更改通知。对于自定义 CLR 绑定源,这意味着该属性必须支持 INotifyPropertyChanged。集合应支持 INotifyCollectionChanged。”

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

Silverlight 中的 DP 与 WPF 之间存在差异。

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

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

于 2011-11-09T10:07:49.730 回答
15

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 或其他任何地方。

于 2009-02-13T19:18:19.077 回答
7

将 ViewModel 依赖项提供给 WPF 真的是一个好主意吗?

.NET 4.0 将具有 System.Xaml.dll,因此您不必依赖于任意框架即可使用它。请参阅Rob Relyea关于他的 PDC 会议的帖子。

我的看法

XAML 是一种描述对象的语言,而 WPF 是一个框架,其描述的对象是 UI 元素。

它们的关系类似于 C#(一种用于描述逻辑的语言)和 .NET(一种实现特定类型逻辑的框架)。

XAML 的目的是声明性对象图。W*F 技术非常适合这种范式,但 XAML 独立于它们而存在。

XAML 和整个依赖系统被实现为 WF 和 WPF 的单独堆栈,可能是为了利用不同团队的经验,而不在它们之间创建依赖关系(没有双关语)。

于 2008-11-14T23:17:19.287 回答
7

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

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

使用 DP,您无法自己定义存储状态的后端。我将不得不让.net 缓存我绑定到的每个状态项的副本。这似乎是不必要的开销——我的状态很大而且很复杂。

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

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

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

于 2008-11-24T17:16:32.707 回答
6

依赖属性是自定义控件创建的粘合剂。如果您有兴趣在 XAML 设计时使用 Intelli-sense 在属性窗口中显示您的属性,则必须使用 Dependency 属性。INPC 永远不会在设计时在属性窗口中显示属性。

于 2014-10-28T21:04:28.717 回答
4

似乎应该在您创建的控件(例如按钮)中使用依赖属性。若要在 XAML 中使用属性并使用所有 WPF 功能,这些属性必须是依赖属性。

但是,您的 ViewModel 最好使用 INotifyPropertyChanged。如果需要,使用 INotifyPropertyChanged 将使您能够拥有 getter/setter 逻辑。

我建议查看 Josh Smith 的已经实现 INotifyPropertyChanged 的​​ ViewModel 的基类版本:

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

我认为这是一个很好的例子来说明如何做一个 ViewModel。

于 2009-03-25T01:59:11.477 回答
4

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

于 2010-09-02T18:37:07.253 回答
3

我更喜欢更直接的方法,我在没有 INotifyPropertyChanged 的​​ Presentation Model中写过博客。使用数据绑定的替代方法,您可以直接绑定到 CLR 属性,而无需任何簿记代码。您只需在视图模型中编写普通的 .NET 代码,它会在您的数据模型更改时更新。

于 2008-12-30T13:15:14.593 回答
3

只有一件事为什么更喜欢 a DependencyObject- Binding 会更好。只需尝试一个带有ListBoxand的示例,TextBox使用来自属性的数据填充列表INotifyPropertyChangedvs.DependencyProperty并编辑来自TextBox...的当前项目

于 2011-03-27T20:18:30.787 回答
0

如果你想向其他控件公开属性,你必须使用依赖属性......但是祝你好运,因为它们需要一段时间才能弄清楚......

于 2011-02-03T21:05:21.793 回答