Silverlight/WPF: Implementing PropertyChanged with Expression Tree
Join the DZone community and get the full member experience.
Join For FreeSource Code: RaisePropertyChangedExample.zip [94.4 KB]
Credits: Thanks to Paul Strong and Soe Moe for sharing this code with me.
Introduction
This article will show you how to implement INotifyPropertyChanged interface with Expression Tree. I’m sure that the most of WPF/Silverlight developer are already familier with implementing INotifyPropertyChanged interface because this is the most important thing that you have to do when you want to notify the changes of property value to the Clients. But here is with Expression Tree. The most of us used to pass the property name as a string to the PropertyChanged event. Why Expression Tree here? Passing the property name as a string doesn’t just work? No, it works but passing a string is not safe. what if you forget to update the string if you are re-naming the Property. The compiler won’t remind you that you have failed to update the string. Of course, you can verify the name like Josh mentioned in his article. But still, you will know only when you run the program. This is where Expression Tree come in. You can use VS Reflector to rename when you are changing the property name. If not, the compiler will remind you to change.
Let’s take a look at the first sample. The class “PageViewModel” implements INotifyPropertyChanged event just as the way that we always do. There is no super cool things inside.
public class PageViewModel : INotifyPropertyChanged
{
private string name = string.Empty;
public string Name
{
get
{
return name;
}
set
{
name = value;
this.RaisePropertyChanged("Name");
}
}
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
But if you are developing the project, there won’t be just one class so implementing INotifyPropertyChanged become tireding process. So, I would suggest to create a base class ( I will call it “ObservableBase ” in this article) so that all classes that need to be implemented INotifyPropertyChanged interface can inherit from that class.
public abstract class ObservableBase : INotifyPropertyChanged
{
public event PropertyChangedEventHandler PropertyChanged;
public void RaisePropertyChanged(string propertyName)
{
if (this.PropertyChanged != null)
{
this.PropertyChanged(this, new PropertyChangedEventArgs(propertyName));
}
}
}
After creating a base class as above, we can change our PageViewModel to inhert from base class so we can completely remove all codes that we used for implementing INotifyPropertyChanged event.
public class PageViewModel : ObservableBase
{
private string name = string.Empty;
public string Name
{
get
{
return name;
}
set
{
name = value;
this.RaisePropertyChanged("Name");
}
}
}
But we are still passing the string to RaisePropertyChanged method. How should we change it to Expression Tree? Yes, we will need to change our base class a little bit. The first thing that come into my mind is that to add one more event that can accept the expression. Let’s check out the sample below.
public void RaisePropertyChanged<TValue>(Expression<Func<TValue>> propertySelector)
{
if (PropertyChanged != null)
{
var memberExpression = propertySelector.Body as MemberExpression;
if (memberExpression != null)
{
PropertyChanged(this, new PropertyChangedEventArgs(memberExpression.Member.Name));
}
}
}
After changing this, we can call that method from setter as below.
private string name = string.Empty;
public string Name
{
get
{
return name;
}
set
{
name = value;
this.RaisePropertyChanged<string>( () => this.Name);
}
}
But why <string>? Is there any way to avoid this? My friend, Soe Moe, come up with the solution that uses C# extension method to avoid having the generic type defined in setter. It’s pretty cool. Please check-out the extension method below.
public static class ObservableBaseEx
{
public static void RaisePropertyChanged<T, TProperty>(this T observableBase, Expression<Func<T, TProperty>> expression) where T : ObservableBase
{
observableBase.RaisePropertyChanged(observableBase.GetPropertyName(expression));
}
public static string GetPropertyName<T, TProperty>(this T owner, Expression<Func<T, TProperty>> expression)
{
var memberExpression = expression.Body as MemberExpression;
if (memberExpression == null)
{
var unaryExpression = expression.Body as UnaryExpression;
if (unaryExpression != null)
{
memberExpression = unaryExpression.Operand as MemberExpression;
if (memberExpression == null)
throw new NotImplementedException();
}
else
throw new NotImplementedException();
}
var propertyName = memberExpression.Member.Name;
return propertyName;
}
}
Finally, we can call the RaisePropertyChanged event without specifing any generic type. Cool, huh?
private string name = string.Empty;
public string Name
{
get
{
return name;
}
set
{
name = value;
this.RaisePropertyChanged( p => p.Name);
}
}
Yes. I’m open to any better solution that you have. Please feel free
to let me know if you have better idea. You can also download my sample
(both WPF and Silverlight included in zip) and play a bit as well.
Thanks for reading!
Published at DZone with permission of Michael Sync. See the original article here.
Opinions expressed by DZone contributors are their own.
Trending
-
What Is Test Pyramid: Getting Started With Test Automation Pyramid
-
Building A Log Analytics Solution 10 Times More Cost-Effective Than Elasticsearch
-
Apache Kafka vs. Message Queue: Trade-Offs, Integration, Migration
-
Build a Simple Chat Server With gRPC in .Net Core
Comments