C# Corner
Using Aspect-Oriented Programming to Initialize and Connect WPF Commands
See how a simple interceptor can help reduce the amount of coding needed to initialize your Windows Presentation Foundation ICommand properties.
As I was recently modifying an existing Windows Presentation Foundation (WPF) project, I grew tired of the repetitive code I was writing to initialize my ICommand objects. I decided that with a little bit of method interception, I could simplify some of this work.
The Magical Notify Property Weaver
As with most programmers, I don't like writing repetitive code. While I'm working on a project, there's usually a point where I find code that could be consolidated into some base class functionality or some other reusable paradigm.
The WPF INotifyPropertyChanged interface is one of those times where code can get extremely repetitive. I used to employ a base class, which had some utility methods that encapsulated property handling and the INotifyPropertyChanged interface. Then I found Simon Cropp's Notify Property Weaver.
This awesome little utility allows you to go back to using simple Microsoft .NET Framework auto-properties in your ViewModel. Cropp's Notify Property Weaver is a post-build task that scans your assembly for classes that implement the INotifyPropertyChanged event. It then rewrites the intermediate language (IL) generated by C# auto-properties and inserts the necessary INotifyPropertyChanged implementation. My ViewModels are much simpler now, and I no longer need to rely on a base class for this functionality.
When I got tired of writing code to initialize my WPF commands, I wondered if there was something similar to Cropp's approach that I could do -- but to do it at runtime as WPF binds to my ViewModel.
The DelegateCommand
I'm using the DelegateCommand that was made popular in the Microsoft Prism framework. I won't go into the details, but the DelegateCommand is an easy way to encapsulate WPF ICommand functionality into a reusable class. If you're using something different, this approach will still work; you'll just need to modify some of the code.
Here's a simple example of exposing some functionality in your ViewModel as an ICommand:
private ICommand showDateCommand;
public ICommand ShowDate
{
get { return showDateCommand ?? (
showDateCommand = new DelegateCommand(() => RunShowDate())); }
}
It's not a lot of code, but it's repeated a number of times throughout my code:
- Define a variable for the ICommand.
- Create a property to expose the ICommand variable.
- If the variable isn't initialized when the getter is called, create a new DelegateCommand that points to the method to run when the command is executed.
The thing I don't like about this is that I have to define both the private variable as well as the public property (along with the DelegateCommand initialization code). Thanks to the Notify Property Weaver, all of my other properties have moved back to being simple auto-properties; I wanted to move my ICommands back to being auto-properties, too. But that means I'd need to somehow "intercept" the WPF calls to my ICommand properties and instantiate the DelegateCommand automatically.
Intercepting Methods
The open source Castle Project contains a project called "Dynamic Proxy." This project allows you to dynamically create a proxy for any non-sealed type. This proxy sits "in between" your calling code and the class instance being called. As you would expect, this is the perfect place to add method interception.
Without going into too much detail, Dynamic Proxy creates a subclass of the type you want to proxy (hence the requirement for non-sealed types) and overrides any virtual members on that type (meaning you can't intercept non-virtual methods).
In effect, the proxy is simply a wrapper around your class. All calls to the wrapper (for example, the proxy) are, by default, directed to the base class implementation (the class you're wrapping). However, we can give Dynamic Proxy an interceptor that will run each time a method is executed.
Dynamic Proxy defines an IInterceptor interface with a single method: Intercept. The first thing I did was create a simple interceptor that would only intercept calls to the getter of my ICommand properties:
public class CommandInterceptor : IInterceptor
{
public void Intercept(IInvocation invocation)
{
if (invocation.Method.ReturnType == typeof(ICommand)
&& invocation.Method.Name.StartsWith("get_"))
{
// Implementation comes next
}
invocation.Proceed();
}
}
The important thing to notice here is the call to invocation.Proceed at the bottom of the method. This tells the proxy to continue with the call to the base class that I proxied. This gives me the flexibility to conditionally execute the base class method or totally replace its functionality.
Now that I had my interception configured, I had to write the code that would create the DelegateCommand, initialize it and return it to WPF.
Creating DelegateCommand at Runtime
Initializing my DelegateCommand is trivial in straight C# code:
showDateCommand = new DelegateCommand(() => RunShowDate())
Doing this at runtime means I'd have to know the name of the method that performs the action of my command. Because the ICommand exposes an "Execute" method, I decided to form a convention that the method for any of my ICommands will be the name of the property prefixed with "Execute_". I'm not a huge fan of underscores in my method names, but this allows me to easily see the methods that are automatically hooked up via my interceptor.
So, in the previous example, I need to create a lambda that points to the method "Execute_ShowDate" (as you recall earlier, my ICommand property is called "ShowDate"). Obviously, I'll also have to rename the current implementation code, RunShowDate, to "Execute_ShowDate." Because lambdas are really just syntactic sugar for delegates, I'll be using the Delegate.CreateDelegate method. Here's the code I'll add to the "// implementation comes next" section:
// Strip off the "get_" prefix on the property getter
var methodName = invocation.Method.Name.Substring(4);
var commandDelegate = Delegate.CreateDelegate(typeof(Action),
invocation.InvocationTarget,
ExecutePrefix + methodName);
In this code, "ExecutePrefix" is a constant defined as "Execute_". Now that I have this, I can create my DelegateCommand and pass this delegate (which represents the lambda) as a constructor argument:
var delegateCommand = Activator.CreateInstance(typeof(DelegateCommand),
new object[] { commandDelegate });
I need to set the return value of the intercepted method (the property getter) to the DelegateCommand I created. I don't want the default invocation to proceed. Because I'm now using auto-properties, the default invocation would simply return the value of the auto-generated backing field, which would be null in this case! Instead, Dynamic Proxy exposes a property on the invocation argument that allows me to set a specific return value:
invocation.ReturnValue = delegateCommand;
return;
I added the return statement so the code doesn't fall through and hit the invocation.Proceed call.
Using the CommandInterceptor
Now that my ViewModel doesn't have to do any of the DelegateCommand creation nor maintain a backing field for my ShowDate command, I can simplify my code to:
public virtual ICommand ShowDate { get; private set; }
private void Execute_ShowDate()
{
//
}
Note that ShowDate is virtual. Dynamic Proxy can only intercept virtual methods/properties. The only other change needed is that my DataContext needs to be a proxy of my ViewModel, not the ViewModel itself. For the sample application that's included with this article, my original DataContext setup code was:
this.DataContext = new MainWindowVM();
Instead, I'll need to create a proxy that uses my CommandInterceptor:
var generator = new ProxyGenerator();
var vm = generator.CreateClassProxy<MainWindowVM>(new CommandInterceptor());
this.DataContext = vm;
This uses the Dynamic Proxy ProxyGenerator to create a proxied instance of my ViewModel, and sets up my CommandInterceptor to intercept all method calls.
Supporting CanExecute
Readers familiar with WPF and the DelegateCommand will note that I didn't address the CanExecute capability. An overload of the DelegateCommand constructor accepts a Func<bool>, which can be used to indicate whether the ICommand can be executed or not. Augmenting my CommandInterceptor with this functionality is fairly easy.
However, there's one big difference between setting up the delegate for Execute and setting up the delegate for CanExecute: the CanExecute is optional. If you recall, my original code for setting up the DelegateCommand was:
showDateCommand = new DelegateCommand(() => RunShowDate())
In this case, the ShowDate command is always available. Often in WPF, I need to enable/disable a command's functionality based on program conditions. In those cases, I pass a delegate that will be used to determine if ShowDate is available:
showDateCommand = new DelegateCommand(() => RunShowDate(), () => CanExecuteShowDate())
I'll go back to the code where I set up my commandDelegate and add a second call to create a canExecuteDelegate. As I did before, I've defined a convention that my CanExecute methods will be prefixed with "CanExecute_" (note code in bold is new code):
var commandDelegate = Delegate.CreateDelegate(typeof(Action),
invocation.InvocationTarget,
ExecutePrefix + methodName);
var canExecuteDelegate = Delegate.CreateDelegate(typeof(Func<bool>),
invocation.InvocationTarget,
CanExecutePrefix + methodName, false, false);
Note the two extra parameters at the end of the CreateDelegate call. The last one tells CreateDelegate to not throw an exception if it can't create a delegate when the method doesn't exist. It will just return null instead. I can use this as an indicator as to whether the ViewModel has defined an appropriate "CanExecute_" method.
Now I just need to determine which overloaded constructor of DelegateCommand to call. This one replaces the previous call to Activator.CreateInstance:
var delegateCommand = Activator.CreateInstance(typeof(Action),
canExecuteDelegate == null
? new object[] { commandDelegate }
: new object[] { commandDelegate, canExecuteDelegate });
Handling DelegateCommand<T>
One last piece I had to handle was the case where the generic version of DelegateCommand was used. The DelegateCommand<T> is used in cases where the XAML defines a CommandParameter that is to be passed to the ICommand Execute and CanExecute methods.
I've defined a convention that the Execute methods for my ICommands will be prefixed with "Execute_", but how do I know if I should create a DelegateCommand or DelegateCommand<T>? Easy -- I can use a little reflection to see if the Execute method accepts a parameter. Once I have this information, I can create the proper, generic versions of Execute, CanExecute and the DelegateCommand.
The first thing I'll do in my interceptor (once I've determined I'm intercepting a property-get on an ICommand) is use reflection to find information about the "Execute_" method defined in the ViewModel:
var mi = invocation.TargetType.GetMethod(ExecutePrefix + methodName,
BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance);
var parameters = mi.GetParameters();
Now, with a list of method parameters, I can tailor the creation of the DelegateCommand. Note how I use the MakeGenericType method on the generic delegate types to create a specific type of delegate (in this case, the type defined by the method's parameter). I've refactored the delegate-creation code so it can support both DelegateCommand and DelegateCommand<T>. The result is seen in Listing 1.
Check out the sample code available for download for a complete sample application. You'll see how one of the ICommands is configured to accept an instance of the ViewModel itself:
public virtual ICommand ToggleEnabled { get; private set; }
private void Execute_ToggleEnabled(MainWindowVM viewModel)
{
viewModel.ButtonEnabled = !viewModel.ButtonEnabled;
}
When the CommandInterceptor looks for "Execute_ToggleEnabled," it will see it has one parameter. Therefore, it will create a delegate of type Action<MainWindowVM> and a DelegateCommand<MainWindowVM>. In the sample code, you'll also see how I have a dictionary to cache the DelegateCommands I create in the interceptor so they only need to be created once per "get" of the ICommand.
Why Not a Base Class?
Instead of using Dynamic Proxy and an interceptor, I could've simply created a base class for all of my ViewModels that contained similar functionality. In fact, if I used the Microsoft .NET Framework 4, I could've had my base ViewModel class inherit from DynamicObject and intercept method calls that way.
First, it seemed a little heavy to create a base class for all of my ViewModels just to do some auto-wiring of the ICommand objects. And because I moved off a ViewModel base class when I started using Notify Property Weaver, I really didn't want to go back to needing a base class.
I've used this in a couple of WPF projects and really like the ease with which I can hook up my ICommand objects. A simple auto-property along with a couple of methods, and everything gets wired up automatically, thanks to my CommandInterceptor.
About the Author
Patrick Steele is a senior .NET developer with Billhighway in Troy, Mich. A recognized expert on the Microsoft .NET Framework, he’s a former Microsoft MVP award winner and a presenter at conferences and user group meetings.