An elegant way to implement INotifyPropertyChanged
Introduction
A very common and popular way to synchronize data between the model and the view in WPF is using DataBinding. The value of the model is transferred to the view once, when the binding is initialized. But for every subsequent change, the model must notify the binding to transfer the value again. This is done by implementing theINotifyPropertyChanged
interface on the model.In the setter of every bound property there must be some code to raise the
PropertyChanged
event, passing the name of the modified property as a string
. This has some disadvantages:- You cannot use Auto-properties
- The property name is passed as a string. This brings ugly errors, when you forgot to change the string after a rename.
- Every property needs extra code
The basic way to do it
private string _name; public string Name { get { return _name; } set { _name = value; PropertyChanged("Name"); } } private void PropertyChanged(string prop) { if( PropertyChanged != null ) { PropertyChanged(this, new PropertyChangedEventArgs(prop); } }
A more elegant way to do it
The basic implementation requires two lines of code in the setter and the property name is passed as a string, which is not very robust. A more elegant solution is to use the power of expression trees to get the property name out of a lambda expression. The result looks like this:private string _name; public string Name { get { return _name; } set { PropertyChanged.ChangeAndNotify(ref _name, value, () => Name); } }
public static bool ChangeAndNotify<T>(this PropertyChangedEventHandler handler, ref T field, T value, Expression<Func<T>> memberExpression) { if (memberExpression == null) { throw new ArgumentNullException("memberExpression"); } var body = memberExpression.Body as MemberExpression; if (body == null) { throw new ArgumentException("Lambda must return a property."); } if (EqualityComparer<T>.Default.Equals(field, value)) { return false; } var vmExpression = body.Expression as ConstantExpression; if (vmExpression != null) { LambdaExpression lambda = Expression.Lambda(vmExpression); Delegate vmFunc = lambda.Compile(); object sender = vmFunc.DynamicInvoke(); if( handler != null) { handler(sender, new PropertyChangedEventArgs(body.Member.Name)); } } field = value; return true; }
- http://blog.decarufel.net/2009/07/how-to-use-inotifypropertychanged-type_22.html
- http://stackoverflow.com/questions/1315621/implementing-inotifypropertychanged-does-a-better-way-exist<7a>
This article is an awesome one which gives an entire information about data binding and how to synchronize data .Thanks for sharing it.
ReplyDeletehttp://www.dapfor.com/en/net-suite/net-grid/features/performance