[PostSharp] Don't NotifyPropertyChanged all properties
By Michael DELVA on Friday 1 October 2010, 14:00 - C# - Permalink
TweetThis article will show you another improvement which can be made to the DataBinding sample aspect found on SharpCrafters, after the Fire INotifyPropertyChanged.OnPropertyChanged for read-only properties depending on other properties article.
By default, the aspect will fire the PropertyChanged event each time any property is changed. But what if you don't want some of them to fire the event? Or what if, as it happened to me, you set the value of a property, and must do some work in the property setter, even if the new value of the property is the same as the old one?
The latter example is a bit odd, but in the default implementation of the aspect, in the OnPropertySet method, you have this code:
if ( args.Value == args.GetCurrentValue() ) return;
args.ProceedSetValue();
If the new value of the property is the same, the aspect will return, and then never call the args.ProceedSetValue(); method, which will avoid your code to be called in the property setter.
In this short article, I'll show you how to change the aspect, to call the OnPropertyChanged event on all properties, excepted those which are marked with a custom attribute.
Let's begin by defining the attribute which will allow some properties to be skipped by the aspect:
[AttributeUsage(AttributeTargets.Property)]
public class DontNotifyAttribute : Attribute
{
}
Pretty simple, isn't it? :)
And now, the aspect.
If you look at the original aspect, you will notice, above the OnPropertySet method the following custom attributes:
[OnLocationSetValueAdvice, MulticastPointcut(Targets = MulticastTargets.Property, Attributes = MulticastAttributes.Instance | MulticastAttributes.NonAbstract)]
What is interesting here if the MulticastPointcut attribute. It defines on which targets the aspect will be applied. In the documentation, it is said that you can use a MethodPointcut which allow you to define a function which will return the targets you want. We then just have to create this function, and replace the MulticastPointcut attribute by MethodPointcut:
private IEnumerable<PropertyInfo> SelectProperties(Type type)
{
const BindingFlags bindingFlags = BindingFlags.Instance | BindingFlags.DeclaredOnly | BindingFlags.Public;
return from property in type.GetProperties(bindingFlags)
where property.CanWrite && !property.IsDefined(typeof(DontNotifyAttribute), true)
select property;
}
[OnLocationSetValueAdvice, MethodPointcut("SelectProperties")]
public void OnPropertySet(LocationInterceptionArgs args)
{
if (args.Value == args.GetCurrentValue())
return;
args.ProceedSetValue();
OnPropertyChangedMethod.Invoke(args.Location.Name);
}
The SelectProperties function will simply return all the properties of the class, without those marked with DontNotifyAttribute.
As simply as that, thanks to the PostSharp framework.
See you soon!