Jul222009
Published by eric at 10:43 PM under .NET Framework | C# | Windows | WPF
Implementation of the INotifyPropertyChanged interface is quite simple. There is only one event to implement. Take for example the following simple model class:
public class Model : INotifyPropertyChanged { private string _data; public string Data { get { return _data; } set { if (_data == value) return; _data = value; // Type un-safe PropertyChanged raise PropertyChanged(this, new PropertyChangedEventArgs("Data")); } } #region Implementation of INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged = null; #endregion }
This is a pretty standard way to implement a bindable property. The problem here is the “Data” string to specify which property changed. If someone change the name of the property without changing the content of the string, the code will compile fine but won’t work. In a big application with may properties it can be hard to detect and find the problem.
The best solution is to rely on the compiler to warn us. But because the property name is a string it can’t. So let’s change that line with a type-safe one.
public class Model : INotifyPropertyChanged { private string _data; public string Data { get { return _data; } set { if (_data == value) return; _data = value; // Type safe PropertyChanged raise PropertyChanged.Raise(() => Data); } } #region Implementation of INotifyPropertyChanged public event PropertyChangedEventHandler PropertyChanged = null; #endregion }
What is the trick? Raise is an extension method that takes a lambda expression to specify the name of the property in a type safe way. The Raise method resolve this expression to extract the name of the property and pass it to the PropertyChanged event.
public static class PropertyChangedExtensions { public static void Raise(this PropertyChangedEventHandler handler, Expression<Func<object>> propertyExpression) { if (handler != null) { // Retreive lambda body var body = propertyExpression.Body as MemberExpression; if (body == null) throw new ArgumentException("'propertyExpression' should be a member expression"); // Extract the right part (after "=>") var vmExpression = body.Expression as ConstantExpression; if (vmExpression == null) throw new ArgumentException("'propertyExpression' body should be a constant expression"); // Create a reference to the calling object to pass it as the sender LambdaExpression vmlambda = Expression.Lambda(vmExpression); Delegate vmFunc = vmlambda.Compile(); object vm = vmFunc.DynamicInvoke(); // Extract the name of the property to raise a change on string propertyName = body.Member.Name; var e = new PropertyChangedEventArgs(propertyName); handler(vm, e); } } }
All you have to do is to put this extension method in your code and the jib is done. Of course at the end a string will be used to raise the PropertyChanged event but because you don’t have to type it, you don’t have to maintain it.
Tags: .net, binding, c#,
E-mail | Permalink | Trackback | Post RSS 0 Responses
Related posts
Comments
Add comment