DependencyProperties or INotifyPropertyChanged ?
When you want to make an object binding-aware you have two choices : implements INotifyPropertyChanged or creates DependencyProperties. Which one is the best ? Let's try to answer this question !How to implement INotifyPropertyChangedDeclaring that your class is implementing INotifyPropertyChang
Is your email address OK? You are signed up for our newsletters but your email address is either unconfirmed, or has not been reconfirmed in a long time. Please clickhere to have a confirmation email sent so we can confirm your email address and start sending you newsletters again. Alternatively, you can update your subscriptions.
When you want to make an object binding-aware you have two choices : implementINotifyPropertyChanged or create DependencyProperties. Which one is the best? Let's try to answer this question!
How to Implement INotifyPropertyChanged
Declaring that your class is implementing INotifyPropertyChanged adds anPropertyChangedEventHandler that you raise for every changes of the properties. We also add a little tricky method checkIfPropertyNameExists(String propertyName) which checks by reflection when debugging if the property name really exists! You usually ends up with code like this :
/// <summary>
/// Base class for all my viewModel.
/// </summary>
public class ViewModelBase : INotifyPropertyChanged
{
#region INotifyPropertyChanged Members
public event PropertyChangedEventHandler PropertyChanged;
public void FirePropertyChanged(String propertyName)
{
checkIfPropertyNameExists(propertyName);
PropertyChangedEventHandler handler = PropertyChanged;
if (handler != null)
handler.Invoke(this, new PropertyChangedEventArgs(propertyName));
} #endregion [Conditional("DEBUG")]
private void checkIfPropertyNameExists(String propertyName)
{
Type type = this.GetType();
Debug.Assert(
type.GetProperty(propertyName) != null,
propertyName + "property does not exist on object of type : " + type.FullName);
}
}
As you can see, the code is quite easy to write and understand. You have to be very vigilant in checking the name of the property you gives as refactoring do not impacts Strings values but it stays quite simple.
DependencyProperties
MSDN definition of a DependencyProperty (link to) : a property that exists on aDependencyObject, is stored by the DependencyObject property store, and is identified by aDependencyProperty identifier on the owning DependencyObject.
Here is an example of how to create a DependencyProperty:
public class MyDependencyObject : System.Windows.DependencyObject
{
public static readonly System.Windows.DependencyProperty MyDependencyPropertyProperty =
System.Windows.DependencyProperty.Register("MyDependencyProperty", typeof(String), typeof(MyDependencyObject)); public String MyDependencyProperty
{
get { return (String)GetValue(MyDependencyObject.MyDependencyPropertyProperty); }
set { SetValue(MyDependencyObject.MyDependencyPropertyProperty, value); }
}
}
Which one choose ?
Performances
All the tests are done under the .NET framework 4.0 with VisualStudio 2010 and .NET Memory Profiler 3.5. The tests were already done on this page MVVM – Lambda vs INotifyPropertyChanged vs DependencyObject but I do not get the same results...
Execution Times
To tests this I created a simple application and two textblocks binded to two String on my ViewModel. The tests were performed one by one and I took care to remove the inheritance of my ViewModel from DependencyObject when testing the INotifyPropertyChanged.
The code used to tests DependencyProperty is this one :
public static readonly DependencyProperty StringWithDependencyPropertyProperty =
DependencyProperty.Register("StringWithDependencyProperty", typeof(String), typeof(MainViewModel));
public String StringWithDependencyProperty
{
get { return (String)GetValue(MainViewModel.StringWithDependencyPropertyProperty); }
set { SetValue(MainViewModel.StringWithDependencyPropertyProperty, value); }
}
...
DateTime start = DateTime.Now;
for (int i = 0; i < 100000; i++)
_mainViewModel.StringWithDependencyProperty = i.ToString();
DateTime end = DateTime.Now;
Console.WriteLine("Total time for DependencyProperty : " + (end - start).TotalMilliseconds +" ms.");
The code used to tests INotifyPropertyChangedis this one :
public String StringWithINotifyPropertyChanged
{
get { return _stringWithINotifyPropertyChanged; }
set
{
_stringWithINotifyPropertyChanged = value;
firePropertyChanged("StringWithINotifyPropertyChanged");
}
}
...
DateTime start = DateTime.Now;
for (int i = 0; i < 100000; i++)
_mainViewModel.StringWithINotifyPropertyChanged = i.ToString();
DateTime end = DateTime.Now;
Console.WriteLine("Total time for INotifyPropertyChanged : " + (end - start).TotalMilliseconds+" ms.");
The results, for NO binding of the properties, were these :
Total time for DependencyProperty : 45 ms.
Total time for INotifyPropertyChanged : 171 ms.
The results, for one binding of the properties, were these :
Total time for DependencyProperty : 489 ms.
Total time for INotifyPropertyChanged : 1125 ms.
The results, for twelve binding of the properties, were these :
Total time for DependencyProperty : 3600ms.
Total time for INotifyPropertyChanged : 8375 ms.
DependencyProperty is 2,30 times faster than INotifyPropertyChanged for one binding and this number does not increase with the number of binded controls!
Edit : As argued in the comments and even if it is not the most common way to useINotifyPropertyChanged, I have made the tests with a static event args, and the results are :
Total time for no binding: 154ms.
Total time for one binding: 770ms.
Total time for twelve bindings: 5605ms.
DependencyProperies are still better, even if it's less...
Memory usage
I executed the same code and profiled the memory usages :
DependencyPropertycreated 600 new instances and add 44,583 bytesINotifyPropertyChangedcreated 876 new instances and add 63,536 bytes
DependencyProperty seems (in my tests) to create less instance and to use less memory than theINotifyPropertyChanged system...
Inheritance Issues
To create a DependencyProperty your objects needs to inherit from DependencyObject. This is not always possible and then using INotifyPropertyChanged is the only way to make it Bindable-aware.
Also, by being a DependencyObject, your object will carry with it all the dependency engine stuff and these limitations:
- only the thread that the
DependencyObjectwas created on may access the DependencyObject directly. DependencyObjectseals Equals and GetHashCode(),- They are not marked as Serializable : (but you can use the XAMLWriter and XAMLReader to do so...
Inheritance from a base class you do not have a grip on ?=> No DependencyProperty !
Animations
Using DependencyProperty make the poperties animatable. If you want to animate a property, there is no simple work-around because, as the MSDN says : In order to be animated, the animation's target property must be a dependency property.
If you can't use DependencyProperty (when you do not create the objects for example), there is still work-arounds techniques.
Flexibility
Using INotifyPropertyChanged is sometimes more flexible than using DependencyProperty. Let me explain that. When you build a screen on which a lot of controls visibility dependsof some rules, you may declare a boolean which value is computed from other boolean.
For example, IsEditionPosible must be set to true only if IsAlreadyInEditionMode = falseand if UserHasEditionRights = true. So when changing the value ofIsAlreadyInEditionMode or UserHasEditionRights you must tells the binding engine thatIsEditionPosible has been updated too. It's easier to do this with INotifyPropertyChangedthan with the DependencyProperty with which you should have to create a method, which recalculate and reassign the new value to IsEditionPosible. Here you just have to use this little snippet :
public Boolean IsAlreadyInEditionMode
{
get { return _isAlreadyInEditionMode ; }
set
{
_isAlreadyInEditionMode = value;
firePropertyChanged("IsAlreadyInEditionMode ");
firePropertyChanged("IsEditionPosible");
}
} public Boolean UserHasEditionRights
{
get { return _userHasEditionRights ; }
set
{
_userHasEditionRights = value;
firePropertyChanged("UserHasEditionRights");
firePropertyChanged("IsEditionPosible");
}
} public Boolean IsEditionPosible
{
get { return UserHasEditionRights && !IsAlreadyInEditionMode ; }
}
Note that this is the way that I create computed value for easier binding in my viewModel but this is a subject where improvments may be done...
Flexibility (easier code writing) needed ?=> Choose INotifyPropertyChanged !
Testing
When you performs testing on your object, you will be in trouble if you use DependencyObject: the test are not done on the same thread that created the object and then throws you a "System.InvalidOperationException: The calling thread cannot access this object because a different thread owns it".
Testing => No DependencyProperty !
Code Readability/Writing
Some people argues that the use of DependencyProperties the code extremely ugly. I myself think that this is exaclty the same. To make easier the creation of dependencyProperty you can use this snippet : link to the snippet
DependencyProperties or INotifyPropertyChanged ?的更多相关文章
- 传智播客--数据绑定--INotifyPropertyChanged(小白内容)
INotifyPropertyChanged一般在数据绑定的时候使用. InotifyPropertyChanged是.net内置的接口,数据绑定时会检测DataContext是否实现了Inotify ...
- INotifyPropertyChanged, Interface
Data Object(class) impliment INotifyPropertyChanged; then the Object can update BindingSource. Impli ...
- Data Binding和INotifyPropertyChanged是如何协调工作的?
前言 WPF的一大基础就是Data Binding.在基于MVVM架构的基础上,只有通过实现INotifyPropertyChanged接口的ViewModel才能够用于Data Binding. 要 ...
- 如何优雅的实现INotifyPropertyChanged接口
INotifyPropertyChanged接口在WPF或WinFrom程序中使用还是经常用到,常用于通知界面属性变更.标准写法如下: class NotifyObject : INotifyProp ...
- INotifyPropertyChanged接口的PropertyChanged 事件
INotifyPropertyChanged 接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知. 例如,考虑一个带有名为 FirstName 属性的 Person 对象. 若要提供 ...
- 为Page添加INotifyPropertyChanged功能
在Page页面里面, DataContext 更新后,前台数据要求会自动更新. 但前台的绑定如果用x:bind 语法. 它要求强类型.直接关联到DataContext上就不行了. 需要为Page 添加 ...
- 【.NET深呼吸】INotifyPropertyChanged接口的真故事
无论是在流氓腾的问问社区,还是在黑度贴吧,或是“厕所等你”论坛上,曾经看到过不少朋友讨论INotifyPropertyChanged接口.不少朋友认为该接口是为双向绑定而使用的,那么,真实的情况是这样 ...
- 使用CallerMemberName简化InotifyPropertyChanged的实现
在WPF中,当我们要使用MVVM的方式绑定一个普通对象的属性时,界面上往往需要获取到属性变更的通知, class NotifyObject : INotifyPropertyChanged ...
- C#-INotifyPropertyChanged(解决数据绑定的界面刷新问题)
最近做项目用到DataGridView,用它绑定数据源后,如果数据源中的数据修改无法及时刷新到控件上,必须切换单元格的焦点才能导致刷新显示新数值,通过查官方文档,用INotifyPropertyCha ...
随机推荐
- CROSS JOIN连接用于生成两张表的笛卡尔集
将两张表的情况全部列举出来 结果表: 列= 原表列数相加 行= 原表行数相乘 CROSS JOIN连接用于生成两张表的笛卡尔集. 在sql中cross join的使用: 1.返回的记录数为两个 ...
- XMPP框架下微信项目总结(4)重新连接服务器
xmpp 很多功能是面向模块开发的 例如电子名片 无须自己去写请求的代码XMPP(文件)->Extension(存放的是各个模块)->Reconnect(自动连接模块) ...
- CLR via C#(11)-无参属性、有参数属性(索引器)
一. 无参属性 1. 定义属性 无参属性就是我们最常见的属性方式,在赋值时可以加入一定的逻辑判断.属性的定义其实不复杂,先看个直观的例子: 说明: 属性要定义名称和类型,且类型不能是void. 属性是 ...
- Faster-rnnlm代码分析1 - 词表构建,Nnet成员
https://github.com/yandex/faster-rnnlm Gdb ./rnnlm r -rnnlm model-good.faster -train thread.titl ...
- SQL链表查询 数据库为空
查询出数据为空,解决方案:链表 对应字段长度不一致.
- Algorithms, Part I by Kevin Wayne, Robert Sedgewick
Welcome to Algorithms, Part I 前言 昨天在突然看到了Coursera上Robert Sedgewick讲的Algorithms,Part II看了一些,甚是爽快,所以又去 ...
- 无废话ExtJs 入门教程五[文本框:TextField]
无废话ExtJs 入门教程五[文本框:TextField] extjs技术交流,欢迎加群(201926085) 继上一节内容,我们在表单里加了个两个文本框.如下所示代码区的第42行位置,items: ...
- OCJP(1Z0-851) 模拟题分析(四)over
Exam : 1Z0-851 Java Standard Edition 6 Programmer Certified Professional Exam 以下分析全都是我自己分析或者参考网上的,定有 ...
- 攻城狮在路上(壹) Hibernate(六)--- 通过Hibernate操纵对象(上)
一.Hibernate缓存简介: Session接口是Hibernate向应用程序提供的操纵数据接口的最主要接口,它提供了基本的保存.更新.删除和加载Java对象的方法. Session具有一个缓存, ...
- <转>Oracle SQL性能优化
原文链接:http://www.cnblogs.com/rootq/archive/2008/11/17/1334727.html (1) 选择最有效率的表名顺序(只在基于规则的优化器中有效 ...