INotifyPropertyChanged auto wiring or how to get rid of redundant code
For the last week most of WPF disciples are discussing how to get rid of hardcoded property name string inside INotifyPropertyChanged implementation and how to keep using automatic properties implementation but keep WPF binding working. The thread was started by Karl Shifflett, who proposed interesting method of using StackFrame for this task. During this thread other methods were proposed including code snippets, R#, Observer Pattern, Cinch framework, Static Reflection, Weak References and others. I also proposed the method we’re using for our classes and promised to blog about it. So the topic today is how to use PostSharp to wire automatic implementation of INotifyPropertyChanged interface based on automatic setters only.
So, I want my code to looks like this:
public class AutoWiredSource {
public double MyProperty { get; set; }
public double MyOtherProperty { get; set; }
}
while be fully noticeable about any change in any property and makes me able to bind to those properties.
<StackPanel DataContext="{Binding Source={StaticResource source}}">
<Slider Value="{Binding Path=MyProperty}" />
<Slider Value="{Binding Path=MyProperty}" />
</StackPanel>
How to achieve it? How to make compiler to replace my code with following?:
private double _MyProperty;
public double MyProperty {
get { return _MyProperty; }
set {
if (value != _MyProperty) {
_MyProperty = value; OnPropertyChanged("MyProperty");
}
}
}
public event PropertyChangedEventHandler PropertyChanged;
internal void OnPropertyChanged(string propertyName) {
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");var handler = PropertyChanged as PropertyChangedEventHandler;
if (handler != null) handler(this, new PropertyChangedEventArgs(propertyName));
}
Simple: to use aspect oriented programming to inject set of instructions into pre-compiled source.
First of all we have to build some attribute will be used for marking classes requires change tracking. This attribute should be combined (compound) aspect to include all aspects used for change tracking. All we’re doing here is to get all set methods to add composition aspect to
[Serializable, DebuggerNonUserCode, AttributeUsage(AttributeTargets.Assembly | AttributeTargets.Class, AllowMultiple = false, Inherited = false),
MulticastAttributeUsage(MulticastTargets.Class, AllowMultiple = false, Inheritance = MulticastInheritance.None, AllowExternalAssemblies = true)]
public sealed class NotifyPropertyChangedAttribute : CompoundAspect {
public int AspectPriority { get; set; }public override void ProvideAspects(object element, LaosReflectionAspectCollection collection) {
Type targetType = (Type)element;
collection.AddAspect(targetType, new PropertyChangedAspect { AspectPriority = AspectPriority });
foreach (var info in targetType.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(pi => pi.GetSetMethod() != null)) {
collection.AddAspect(info.GetSetMethod(), new NotifyPropertyChangedAspect(info.Name) { AspectPriority = AspectPriority });
}
}
}
Next aspect is change tracking composition aspect. Which is used for marking only
[Serializable]
internal sealed class PropertyChangedAspect : CompositionAspect {
public override object CreateImplementationObject(InstanceBoundLaosEventArgs eventArgs) {
return new PropertyChangedImpl(eventArgs.Instance);
}public override Type GetPublicInterface(Type containerType) {
return typeof(INotifyPropertyChanged);
}public override CompositionAspectOptions GetOptions() {
return CompositionAspectOptions.GenerateImplementationAccessor;
}
}
And the next which is most interesting one, we will put onto method boundary for tracking. There are some highlights here. First we do not want to fire PropertyChanged event if the actual value did not changed, thus we’ll handle the method on it entry and on it exit for check.
[Serializable]
internal sealed class NotifyPropertyChangedAspect : OnMethodBoundaryAspect {
private readonly string _propertyName;public NotifyPropertyChangedAspect(string propertyName) {
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");
_propertyName = propertyName;
}public override void OnEntry(MethodExecutionEventArgs eventArgs) {
var targetType = eventArgs.Instance.GetType();
var setSetMethod = targetType.GetProperty(_propertyName);
if (setSetMethod == null) throw new AccessViolationException();
var oldValue = setSetMethod.GetValue(eventArgs.Instance,null);
var newValue = eventArgs.GetReadOnlyArgumentArray()[0];
if (oldValue == newValue) eventArgs.FlowBehavior = FlowBehavior.Return;
}public override void OnSuccess(MethodExecutionEventArgs eventArgs) {
var instance = eventArgs.Instance as IComposed<INotifyPropertyChanged>;
var imp = instance.GetImplementation(eventArgs.InstanceCredentials) as PropertyChangedImpl;
imp.OnPropertyChanged(_propertyName);
}
}
We almost done, all we have to do is to create class which implements INotifyPropertyChanged with internal method to useful call
[Serializable]
internal sealed class PropertyChangedImpl : INotifyPropertyChanged {
private readonly object _instance;public PropertyChangedImpl(object instance) {
if (instance == null) throw new ArgumentNullException("instance");
_instance = instance;
}public event PropertyChangedEventHandler PropertyChanged;
internal void OnPropertyChanged(string propertyName) {
if (string.IsNullOrEmpty(propertyName)) throw new ArgumentNullException("propertyName");var handler = PropertyChanged as PropertyChangedEventHandler;
if (handler != null) handler(_instance, new PropertyChangedEventArgs(propertyName));
}
}
We done. The last thing is to reference to PostSharp Laos and Public assemblies and mark compiler to use Postsharp targets (inside your project file (*.csproj)
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<PropertyGroup>
<DontImportPostSharp>True</DontImportPostSharp>
</PropertyGroup>
<Import Project="PostSharp\PostSharp-1.5.targets" />
Now we done. We can use clear syntax like following to make all our properties has public setter to be traceable. The only disadvantage is that you’ll have to drag two Post Sharp files with your project. But after all it much more convenience than manual notify change tracking all over your project.
[NotifyPropertyChanged]
public class AutoWiredSource {
public double MyProperty { get; set; }
}
Have a nice day and be good people. Also try to thing what other extremely useful things can be done with PostSharp (or any other aspect oriented engine)
Source code for this article (1,225 KB)>>
You may also be interested with:
- RSA private key import from PEM format in C#
- Video encoder and metadata reading by using Windows Media Foundation
August 9th, 2009 · Comments (6)
6 Responses to “INotifyPropertyChanged auto wiring or how to get rid of redundant code”
Leave a Reply
Discover other tags
My tools
- .NET Framework Detector
- Duplicate images finder
- Exchange Security Policy for Windows Mobile Devices Fix
- Gas Price Windows Vista SideBar gadget
- Israel Traffic Information Windows Vista SideBar gadget
- Localization fix for SAP ES Explorer for Visual Studio
- LocTester
- RTL and LTR in Windows Live Writer
- Silverlight controls library
- Snipping tool integration plugin for WLW
- USB FM receiver library
- Vista Battery Saver
- WebCam control for WPF
- Windows Live SkyDrive attachment for Windows Live Writer
- Wireless Migrator
- WPF Virtual Keyboard





August 10th, 2009 at 6:05 am
I didn’t see proxies on your list? Did I miss it? I’ve been experimenting (with some success) using DynamicProxy2. I know that several others have as well.
August 10th, 2009 at 10:53 am
it is not nessecery to use proxy in this case. All you need is to invoke a method inside the setter of the property
August 27th, 2009 at 12:14 am
Great article! However my great concern is performance. I’m 100% sure that you will get a dramatical performance impact when using such approach. Do you have a comparison benchmarks for large objects amount?
September 24th, 2009 at 7:33 am
Thank you for blogging about PostSharp.
As the author of PostSharp, I’m not proud of this code sample, because it’s not as nice as it could.
The same aspect will be implemented in a much more elegant manner in PostSharp 2.0, and it’s runtime performance will be much better.
See http://www.postsharp.org/blog/introducing-postsharp-20-1-notifypropertychanged for the full story.
September 24th, 2009 at 8:35 pm
Thank you for paying attention to such problems. I will fix this article soon
December 7th, 2009 at 6:42 pm
There’s certainly nothing to be ashamed of with PostSharp, it’s an excellent code set and quite useful for someone like myself – thank you for your efforts (and this post).