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 :

Copy Code

/// <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:

Copy Code

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 :

Copy Code

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 :

Copy Code

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 :

DependencyProperty created 600 new instances and add 44,583 bytesINotifyPropertyChanged created 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:

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 :

Copy Code

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 ?的更多相关文章

  1. 传智播客--数据绑定--INotifyPropertyChanged(小白内容)

    INotifyPropertyChanged一般在数据绑定的时候使用. InotifyPropertyChanged是.net内置的接口,数据绑定时会检测DataContext是否实现了Inotify ...

  2. INotifyPropertyChanged, Interface

    Data Object(class) impliment INotifyPropertyChanged; then the Object can update BindingSource. Impli ...

  3. Data Binding和INotifyPropertyChanged是如何协调工作的?

    前言 WPF的一大基础就是Data Binding.在基于MVVM架构的基础上,只有通过实现INotifyPropertyChanged接口的ViewModel才能够用于Data Binding. 要 ...

  4. 如何优雅的实现INotifyPropertyChanged接口

    INotifyPropertyChanged接口在WPF或WinFrom程序中使用还是经常用到,常用于通知界面属性变更.标准写法如下: class NotifyObject : INotifyProp ...

  5. INotifyPropertyChanged接口的PropertyChanged 事件

    INotifyPropertyChanged 接口用于向客户端(通常是执行绑定的客户端)发出某一属性值已更改的通知. 例如,考虑一个带有名为 FirstName 属性的 Person 对象. 若要提供 ...

  6. 为Page添加INotifyPropertyChanged功能

    在Page页面里面, DataContext 更新后,前台数据要求会自动更新. 但前台的绑定如果用x:bind 语法. 它要求强类型.直接关联到DataContext上就不行了. 需要为Page 添加 ...

  7. 【.NET深呼吸】INotifyPropertyChanged接口的真故事

    无论是在流氓腾的问问社区,还是在黑度贴吧,或是“厕所等你”论坛上,曾经看到过不少朋友讨论INotifyPropertyChanged接口.不少朋友认为该接口是为双向绑定而使用的,那么,真实的情况是这样 ...

  8. 使用CallerMemberName简化InotifyPropertyChanged的实现

    在WPF中,当我们要使用MVVM的方式绑定一个普通对象的属性时,界面上往往需要获取到属性变更的通知,     class NotifyObject : INotifyPropertyChanged   ...

  9. C#-INotifyPropertyChanged(解决数据绑定的界面刷新问题)

    最近做项目用到DataGridView,用它绑定数据源后,如果数据源中的数据修改无法及时刷新到控件上,必须切换单元格的焦点才能导致刷新显示新数值,通过查官方文档,用INotifyPropertyCha ...

随机推荐

  1. 晨跑(bzoj 1877)

    Description Elaxia最近迷恋上了空手道,他为自己设定了一套健身计划,比如俯卧撑.仰卧起坐等 等,不过到目前为止,他坚持下来的只有晨跑. 现在给出一张学校附近的地图,这张地图中包含N个十 ...

  2. 使用vsphere client 克隆虚拟机

    免费的VMWare ESXi5.0非常强大,于是在vSphere5.0平台中ESXi取代了ESX.,使用ESXi经常会遇到这样的问题,我需要建立多个虚拟机,都是windows2003操作系统,难道必须 ...

  3. volatile和const

    volatile可理解为“编译器警告指示字” volatile用于告诉编译器必须每次去内存中取变量值 volatile主要修饰可能被多个线程访问的变量 volatile也可以修饰可能被未知因数更改的变 ...

  4. 第一个JAVA创建

    1.file-new-java project  创建项目文件夹 2.在项目文件夹new-class 3.java对大小写比较敏感 输入代码 public class HELLOWORD { publ ...

  5. VGA信号一些分辨率的参数(摘抄)

    摘抄自:http://group.chinaaet.com/273/4100029440 VGA的接口时序如图所示,场同步信号VSYNC在每帧(即送一次全屏的图像)开始的时候产生一个固定宽度的高脉冲, ...

  6. PHP 获取图像信息 getimagesize 函数

    getimagesize() 函数用于获取图像尺寸,类型等信息. imagesx() 函数用于获取图像的宽度. imagesy() 函数用于获取图像的高度. getimagesize() getima ...

  7. 【翻译二十一】java-并发之分拆和合并

    Fork/Join This section was updated to reflect features and conventions of the upcoming Java SE 8 rel ...

  8. 无废话ExtJs 入门教程二[Hello World]

    无废话ExtJs 入门教程二[Hello World] extjs技术交流,欢迎加群(201926085) 我们在学校里学习任何一门语言都是从"Hello World"开始,这里我 ...

  9. HDU1899 Sum the K-th's(树状数组)

    枚举,每次增加点,删除点 #include<cstdio> #include<iostream> #include<cstdlib> #include<cst ...

  10. long和int的区别

    转自:http://blog.sina.com.cn/s/blog_6f62c9510101svjz.html 突然间就想到了long和int到底什么区别(发现有很多问题都是突然间想到的),然后百度. ...