Click here to Skip to main content
15,885,546 members
Articles / Desktop Programming / WPF

MVVM - Creating ViewModel : create dynamic proxies with Castle (solution 3 of n)

Rate me:
Please Sign up or sign in to vote.
4.00/5 (5 votes)
12 Mar 2010Ms-PL3 min read 21.6K   8   2
Here is the next episode of our serie MVVM - Creating ViewModel.

Here is the next episode of our serie MVVM - Creating ViewModel. A list of all the articles about creating a ViewModel is here.

Today we are going to see how to create dynamic proxies for our business objects.

What are Dynamic Proxies ?

Readers in a hurry can directly jump to the third part "An implementation".

Proxies are a Design Pattern which are used a lot in our computer programming world. Here is the Wikipedia definition:

A proxy, in its most general form, is a class functioning as an interface to something else. The proxy could interface to anything: a network connection, a large object in memory, a file, or some other resource that is expensive or impossible to duplicate.

The easiest example to understand I have found is sunglasses. The sunglasses are a proxy between the real world (with all the funky colors) and the world you see through them (where everything is grey/brown)... You also noticed that the proxy is not neutral, it adds a behavior(here the gray filter on your vision), but this is not mandatory.
Note: Laurent pointed out that he prefers the TV analogy to explain proxies, but I prefer the sunglasses in which there is no transformations 3D to 2D.

Proxies

With this in mind, let met introduce some vocabulary:

  • The subject: This is the proxied object. In our case: the real world
  • The client: This is the object which wants to use the subject. In our case, the one who wears the sunglasses
  • The proxy: This is the object used by the client and which uses the subject. In our case: the sunglasses
  • The behaviors/interceptors: This is a behavior that the subject does not have and that the proxy creates. In a program, a common interceptor is a logger which tells the start and the end of a method.

Behavior algo example:

C#
public void loggerExampleBehavior(Method theMethod){
  Log("Before method execution.");
  //Execution of the method
  Log("After method execution.");
}

So How To Use Them for our ViewModel? (Theory)

Readers in a hurry can directly jump to the third part, "An implementation".

To be brief: we will add the INotifyPropertyChanged behavior to the business objects by creating a dynamicProxy. We will then no more directly use the business object but the proxies of/to them.
We will so launch the PropertyChangedEvent for each call made to a setter of the business object. Pretty simple ?

proxies_INotify_logic.jpg

An Implementation with Castle dynamicProxy (Code)

To implement the proxy pattern dynamically, we will use Castle Dynamic Proxy. This framework is pretty simple to use as you'll see.

There is only one limitation: properties of your business object must be marked as virtual.

Creation of the Proxy

To create our proxy, I declare a static method. This method is generic and makes any object send NotifyPropertyChanged events on setter calls. The different classes used will be described later.

C#
public class ProxyCreator
{
  public static T MakeINotifyPropertyChanged<T>() where T : class, new()
  {
    //Creates a proxy generator
    ProxyGenerator proxyGen = new ProxyGenerator();
 
    //Generates a proxy using our Interceptor and implementing INotifyPropertyChanged
    var proxy = proxyGen.CreateClassProxy(
      typeof(T),
      new Type[] { typeof(INotifyPropertyChanged) },
      ProxyGenerationOptions.Default,
      new NotifierInterceptor()
      );
 
    return proxy as T;
  }
}

The Interceptor

The interceptor does two main things:

  1. It exposes a PropertyChangedEventHandler
  2. It raises the PropertyChangedEventHandler event when a setter is called with the good name

Also, I have cached the PropertyChangedEventArgs for better performance.

C#
public class NotifierInterceptor : IInterceptor
{
  private PropertyChangedEventHandler handler;
  public static Dictionary<String, PropertyChangedEventArgs> _cache =
    new Dictionary<string, PropertyChangedEventArgs>();
 
  public void Intercept(IInvocation invocation)
  {
    //Each subscription to the PropertyChangedEventHandler is intercepted (add)
    if (invocation.Method.Name == "add_PropertyChanged")
    {
      handler = (PropertyChangedEventHandler)
            Delegate.Combine(handler, (Delegate)invocation.Arguments[0]);
      invocation.ReturnValue = handler;
    }
    //Each de-subscription to the PropertyChangedEventHandler is intercepted (remove)
    else if (invocation.Method.Name == "remove_PropertyChanged")
    {
      handler = (PropertyChangedEventHandler)
         Delegate.Remove(handler, (Delegate)invocation.Arguments[0]);
      invocation.ReturnValue = handler;
    }
    //Each setter raise a PropertyChanged event
    else if (invocation.Method.Name.StartsWith("set_"))
    {
      //Do the setter execution
      invocation.Proceed();
      //Launch the event after the execution
      if (handler != null)
      {
        PropertyChangedEventArgs arg =
          retrievePropertyChangedArg(invocation.Method.Name);
        handler(invocation.Proxy, arg);
      }
    }
    else invocation.Proceed();
  }
 
  // Caches the PropertyChangedEventArgs
  private PropertyChangedEventArgs retrievePropertyChangedArg(String methodName)
  {
    PropertyChangedEventArgs arg = null;
    NotifierInterceptor._cache.TryGetValue(methodName, out arg);
    if (arg == null)
    {
      arg = new PropertyChangedEventArgs(methodName.Substring(4));
      NotifierInterceptor._cache.Add(methodName, arg);
    }
    return arg;
  }
}

How We Use It in the Application

We'll only have to expose the proxies to our views with a little snippet of code:

C#
MyBusinessObject myBusinessObject;
DataContext = myBusinessObject = 
	ProxyCreator.MakeINotifyPropertyChanged<MyBusinessObject>();

Interesting Links

Shout it kick it on DotNetKicks.com
This article was originally posted at http://blog.lexique-du-net.com/index.php

License

This article, along with any associated source code and files, is licensed under The Microsoft Public License (Ms-PL)


Written By
Software Developer http://wpf-france.fr
France (Metropolitan) France (Metropolitan)
Jonathan creates software, mostly with C#,WPF and XAML.

He really likes to works on every Natural User Interfaces(NUI : multitouch, touchless, etc...) issues.



He is awarded Microsoft MVP in the "Client Application Development" section since 2011.


You can check out his WPF/C#/NUI/3D blog http://www.jonathanantoine.com.

He is also the creator of the WPF French community web site : http://wpf-france.fr.

Here is some videos of the projects he has already work on :

Comments and Discussions

 
GeneralExcellent article! Pin
Kirill Balandin13-Mar-10 13:29
Kirill Balandin13-Mar-10 13:29 
GeneralRe: Excellent article! Pin
jmix9014-Mar-10 2:09
jmix9014-Mar-10 2:09 
Thank you ! Big Grin | :-D

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.