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:

http://github.com/RookieOne/StructureMapAopNotify

Share your opinion! Post your thoughts.