在Model-View-ViewModel体系结构WPF应用程序中实现ViewModel时,似乎有两个主要选择如何使其成为databindable . 我已经看到使用 DependencyProperty 实现View将要绑定的属性的实现,我已经看到了实现 INotifyPropertyChanged 的ViewModel .
DependencyProperty
INotifyPropertyChanged
我的问题是我应该何时优先选择其中一个?有任何性能差异吗?将ViewModel依赖项提供给WPF真的是个好主意吗?做出设计决定时还需要考虑什么?
选择完全基于您的业务逻辑和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 是一个更加明确的机制 .
string
依赖属性意味着“当这样做时,使用易于理解的静态元数据” . 这是一种声明性的方法,让我对优雅的投票 .
肯特写了一篇关于这个话题的有趣博客:View Models: POCOs versus DependencyObjects .
Short summary:
DependencyObjects未标记为可序列化
DependencyObject类重写并密封Equals()和GetHashCode()方法
DependencyObject具有线程关联性 - 只能在创建它的线程上访问它
我更喜欢POCO方法 . 可以在此处找到实现INotifyPropertyChanged接口的PresentationModel(也称为ViewModel)的基类:http://compositeextensions.codeplex.com
根据WPF性能指南,DependencyObjects肯定比实现INotifyPropertyChanged的POCO表现更好:
http://msdn.microsoft.com/en-us/library/bb613546.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,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的用武之地 . 从纯粹的角度来看,不应该在ViewModel上使用DP .
“为了成为绑定的源,属性不需要是依赖属性;您可以使用任何CLR属性作为绑定源 . 但是,为了成为绑定的目标,属性必须是依赖属性 . 要使单向或双向绑定生效,源属性必须支持传播到绑定系统并因此传播到目标的更改通知 . 对于自定义CLR绑定源,这意味着该属性必须支持INotifyPropertyChanged . 集合应该支持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
我最近也不得不考虑这个决定 .
我发现INotifyPropertyChanged机制更适合我的需求,因为它允许我将GUI粘贴到现有的业务逻辑框架而不会重复状态 . 我使用的框架有自己的观察者模式,很容易将一个级别的通知转发到下一个 . 我只是有一个类,它从我的业务逻辑框架和INotifyPropertyChanged接口实现了观察者接口 .
使用DP,您无法定义自己存储状态的后端 . 我不得不让.net缓存我绑定的每个状态项的副本 . 这似乎是一种不必要的开销 - 我的状态庞大而复杂 .
所以在这里我发现INotifyPropertyChanged更好地将属性从业务逻辑暴露到GUI .
这就是说,我需要一个自定义GUI小部件来公开一个属性,并且对该属性的更改影响其他GUI小部件,DP证明了这个简单的解决方案 .
我有发现DP对GUI到GUI通知很有用 .
将ViewModel依赖项提供给WPF真的是个好主意吗?
.NET 4.0将具有System.Xaml.dll,因此您不必依赖任意框架来使用它 . 有关他的PDC会话,请参阅Rob Relyea's帖子 .
My take
XAML是用于描述对象的语言,WPF是一个框架,其描述的对象是UI元素 .
它们的关系类似于C#,一种用于描述逻辑的语言,以及.NET,一种实现特定逻辑的框架 .
XAML的目的是声明性对象图 . W * F技术是这种范例的理想选择,但XAML独立存在 .
XAML和整个依赖系统是作为WF和WPF的单独堆栈实现的,可能是为了利用不同团队的经验而不会在它们之间创建依赖(没有双关语) .
依赖属性是自定义控件创建的 Binders . 如果您有兴趣使用Intelli-sense在XAML设计时在属性窗口中显示属性,则必须使用依赖项属性 . INPC将不会在设计时在属性窗口中显示属性 .
似乎应该在您创建的控件(如按钮)中使用依赖项属性 . 要在XAML中使用属性并使用所有WPF功能,这些属性必须具有依赖项属性 .
但是,使用INotifyPropertyChanged最好使用ViewModel . 如果需要,使用INotifyPropertyChanged将使您能够具有getter / setter逻辑 .
我建议查看Josh Smith的已经实现了INotifyPropertyChanged的ViewModel的基类版本:
http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/
我认为这是如何做ViewModel的一个很好的例子 .
我认为DependencyProperty和INotifyPropertyChanged在Binding中用于两个不同的东西:第一个用于启用属性作为绑定的目标并从另一个属性接收输入(使用来设置属性),最后一个当您希望将属性的值用作绑定的源(绑定路径表达式中的名称)时 . 所以选择仅仅是技术性的 .
我更喜欢更直接的方法,我在_913480中发表了博客文章 . 使用数据绑定的替代方法,您可以直接绑定到CLR属性,而无需任何簿记代码 . 您只需在View Model中编写普通的.NET代码,并在数据模型更改时进行更新 .
只有一件事为什么更喜欢 DependencyObject - Binding会更好用 . 试试一个带有 ListBox 和 TextBox 的示例,使用 INotifyPropertyChanged 属性与 DependencyProperty 中的数据填充列表,并编辑 TextBox 中的当前项目...
DependencyObject
ListBox
TextBox
如果要将属性公开给其他控件,则必须使用依赖属性...但祝你好运,因为他们需要一段时间来弄清楚......
14 回答
选择完全基于您的业务逻辑和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
是一个更加明确的机制 .依赖属性意味着“当这样做时,使用易于理解的静态元数据” . 这是一种声明性的方法,让我对优雅的投票 .
肯特写了一篇关于这个话题的有趣博客:View Models: POCOs versus DependencyObjects .
Short summary:
DependencyObjects未标记为可序列化
DependencyObject类重写并密封Equals()和GetHashCode()方法
DependencyObject具有线程关联性 - 只能在创建它的线程上访问它
我更喜欢POCO方法 . 可以在此处找到实现INotifyPropertyChanged接口的PresentationModel(也称为ViewModel)的基类:http://compositeextensions.codeplex.com
根据WPF性能指南,DependencyObjects肯定比实现INotifyPropertyChanged的POCO表现更好:
http://msdn.microsoft.com/en-us/library/bb613546.aspx
INotifyPropertyChanged
使用时还可以在getter的代码和属性的setter中添加更多逻辑 .DependencyProperty
示例:在你的getter和setter ---所有你能做的只是分别调用SetValue和GetValue,b / c在框架的其他部分没有调用getter / setter,而是直接调用SetValue,GetValue,所以你的属性逻辑不会可靠地执行 .
使用
INotifyPropertyChanged
,定义一个事件:然后在代码中的任何地方放置任何逻辑,然后调用:
这可能是在getter / setter或其他任何地方 .
依赖属性旨在支持UI元素上的绑定(作为目标)而不是数据绑定的源,这是INotifyProperty的用武之地 . 从纯粹的角度来看,不应该在ViewModel上使用DP .
“为了成为绑定的源,属性不需要是依赖属性;您可以使用任何CLR属性作为绑定源 . 但是,为了成为绑定的目标,属性必须是依赖属性 . 要使单向或双向绑定生效,源属性必须支持传播到绑定系统并因此传播到目标的更改通知 . 对于自定义CLR绑定源,这意味着该属性必须支持INotifyPropertyChanged . 集合应该支持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
我最近也不得不考虑这个决定 .
我发现INotifyPropertyChanged机制更适合我的需求,因为它允许我将GUI粘贴到现有的业务逻辑框架而不会重复状态 . 我使用的框架有自己的观察者模式,很容易将一个级别的通知转发到下一个 . 我只是有一个类,它从我的业务逻辑框架和INotifyPropertyChanged接口实现了观察者接口 .
使用DP,您无法定义自己存储状态的后端 . 我不得不让.net缓存我绑定的每个状态项的副本 . 这似乎是一种不必要的开销 - 我的状态庞大而复杂 .
所以在这里我发现INotifyPropertyChanged更好地将属性从业务逻辑暴露到GUI .
这就是说,我需要一个自定义GUI小部件来公开一个属性,并且对该属性的更改影响其他GUI小部件,DP证明了这个简单的解决方案 .
我有发现DP对GUI到GUI通知很有用 .
.NET 4.0将具有System.Xaml.dll,因此您不必依赖任意框架来使用它 . 有关他的PDC会话,请参阅Rob Relyea's帖子 .
My take
XAML是用于描述对象的语言,WPF是一个框架,其描述的对象是UI元素 .
它们的关系类似于C#,一种用于描述逻辑的语言,以及.NET,一种实现特定逻辑的框架 .
XAML的目的是声明性对象图 . W * F技术是这种范例的理想选择,但XAML独立存在 .
XAML和整个依赖系统是作为WF和WPF的单独堆栈实现的,可能是为了利用不同团队的经验而不会在它们之间创建依赖(没有双关语) .
依赖属性是自定义控件创建的 Binders . 如果您有兴趣使用Intelli-sense在XAML设计时在属性窗口中显示属性,则必须使用依赖项属性 . INPC将不会在设计时在属性窗口中显示属性 .
似乎应该在您创建的控件(如按钮)中使用依赖项属性 . 要在XAML中使用属性并使用所有WPF功能,这些属性必须具有依赖项属性 .
但是,使用INotifyPropertyChanged最好使用ViewModel . 如果需要,使用INotifyPropertyChanged将使您能够具有getter / setter逻辑 .
我建议查看Josh Smith的已经实现了INotifyPropertyChanged的ViewModel的基类版本:
http://joshsmithonwpf.wordpress.com/2007/08/29/a-base-class-which-implements-inotifypropertychanged/
我认为这是如何做ViewModel的一个很好的例子 .
我认为DependencyProperty和INotifyPropertyChanged在Binding中用于两个不同的东西:第一个用于启用属性作为绑定的目标并从另一个属性接收输入(使用来设置属性),最后一个当您希望将属性的值用作绑定的源(绑定路径表达式中的名称)时 . 所以选择仅仅是技术性的 .
我更喜欢更直接的方法,我在_913480中发表了博客文章 . 使用数据绑定的替代方法,您可以直接绑定到CLR属性,而无需任何簿记代码 . 您只需在View Model中编写普通的.NET代码,并在数据模型更改时进行更新 .
只有一件事为什么更喜欢
DependencyObject
- Binding会更好用 . 试试一个带有ListBox
和TextBox
的示例,使用INotifyPropertyChanged
属性与DependencyProperty
中的数据填充列表,并编辑TextBox
中的当前项目...如果要将属性公开给其他控件,则必须使用依赖属性...但祝你好运,因为他们需要一段时间来弄清楚......