Aop INotifyPropertyChanged StructureMap
Anyone who has worked with INotifyPropertyChanged knows that this simple interface can be a royal pain in the ass.
To try and eliminate the pain, people have created some great solutions using AOP : IL weaving (PostSharp) and using a proxy (Castle Dynamic Proxy).
PostSharp has a little too much voodoo for me atm. I think I will warm up to it though and re-examine using PostSharp on my next solution. But for now, I wanted to use Castle Project’s Dynamic Proxy.
Naturally since Castle also has a very popular IoC container in Windsor, most examples marry Dynamic Proxy and Windsor to form an AOP INotifyPropertyChanged solution.
Since I am using StructureMap for this project, I endeavored to create my own solution using Dynamic Proxy.
My first attempt I shared at the Virtual Brown Bag look liked it worked but in reality I was constructing my objects twice.
Once with SM and once with the Proxy generator.
I had to go back to the drawing board and posted my problem at the SM google group. http://groups.google.com/group/structuremap-users/browse_thread/thread/1a6b19ce8152db1b?hl=en
I believe the syntax given to me was an older version of SM. For the record, I am using version 2.5.3.0
But it did direct me to the general idea on where I should start looking. I ended up needing to create an IBuildInterceptor.
public class MyBuildInterceptor : IBuildInterceptor { public MyBuildInterceptor(Type concreteType) { _ConcreteType = concreteType; } readonly Type _ConcreteType; public object Build(BuildSession buildSession, Type pluginType, Instance instance) { var constructorArgs = _ConcreteType .GetConstructors() .FirstOrDefault() .GetParameters() .Select(p => buildSession.CreateInstance(p.ParameterType)) .ToArray(); var interceptors = new List<IInterceptor> { new NotifyInterceptor() } .ToArray(); return new ProxyGenerator().CreateClassProxy(_ConcreteType, interceptors, constructorArgs); } public IBuildPolicy Clone() { return InnerPolicy.Clone(); } public void EjectAll() { InnerPolicy.EjectAll(); } public IBuildPolicy InnerPolicy { get; set; } }
To register my ViewModels I created a convention using a TypeScanner
public class MyNotifyConvention : ITypeScanner{ public void Process(Type type, PluginGraph graph) { if (type.GetInterface("IViewModel") == null) return; var interfaceType = type.GetInterfaces().FirstOrDefault(i => i.Name.Contains("ViewModel") && i.Name != "IViewModel"); if (interfaceType == null) return; graph.Configure(r => r.ForRequestedType(interfaceType) .InterceptConstructionWith(new MyBuildInterceptor(type)) .TheDefaultIsConcreteType(type)); }}
I then used a Dynamic Proxy Interceptor that I basically copy and pasted from Serial Seb’s example.
public class NotifyInterceptor : IInterceptor{ public void Intercept(IInvocation invocation) { // let the original call go through first, so we can notify *after* invocation.Proceed(); if (invocation.Method.Name.StartsWith("set_")) { string propertyName = invocation.Method.Name.Substring(4); RaisePropertyChangedEvent(invocation, propertyName, invocation.TargetType); } } void RaisePropertyChangedEvent(IInvocation invocation, string propertyName, Type type) { // get the field storing the delegate list that are stored by the event. var methodInfo = type.GetMethod("RaisePropertyChanged"); if (methodInfo == null) { if (type.BaseType != null) RaisePropertyChangedEvent(invocation, propertyName, type.BaseType); } else // info != null { methodInfo.Invoke(invocation.InvocationTarget, new object[] {propertyName}); } }}
Instead of looking for the PropertyChanged Handler, I create a RaisePropertyChanged method and use that. Although I could raise the event using the field method Seb was using, WPF wasn’t updating the binding. I didn’t really bother to investigate and just rolled with this solution.
So that’s my solution and I’ll start using it in my current solution. Naturally I will clean up the code some more etc. Feel free to use this for any of your own projects. You can also get the solution at my GitHub:

