Introduction
Through the use of the Windows Presentation Foundation's (WPF) advanced data-binding capabilities, the logical structure of a user interface can relatively easily be disconnected from its presentation. Bindable components can now contain nearly all of an application's user interface logic, and in most circumstances, replace the need for controller objects from the classic Model-View-Controller (MVC) pattern. So it's no wonder that a new pattern for UI design has appeared. The controller has now been replaced with the View Model in the Model-View-ViewModel (MVVM) pattern for UI design.
At first, it seems that we finally have a Windows presentation technology that fully supports data binding (and templating), but when we dig a little deeper, we find that there is a gap in what we need and what WPF offers. Binding the presentation layer directly to the properties of a view model works like a charm, but binding user input to the methods of the view model doesn't work at all. Many developers have contributed functional solutions to this problem that leverage features of the WPF Commanding architecture. These solutions use custom command objects as a means to adapt the property binding capabilities of WPF to the methods of view models. This approach, however, sacrifices the core value provided by the WPF commanding architecture, and requires us to add command properties to our view models. The command properties have no value other than serving as an adapter for WPF.
The RoutedCommandBinding
class described by this article solves these problems. Using a specific implementation of this class (DataContextCommandBinding
), developers can invoke methods in the view model directly from XAML, taking full advantage of the WPF commanding architecture and requiring no command objects in our view models.
The image below shows the simplicity of the approach. It illustrates the logical path that a command takes:
- Command invoked by a
Button
- Command received by a
DataContextCommandBinding
- Command relayed to a method of the view model
Background: Understanding the WPF Input System
WPF does a really good job of abstracting developers away from the details of capturing user input. Basically, device input is captured by the WPF input subsystem, and then nice clean input events popup on our WPF elements. There are two mechanisms that can be used to invoke application behavior when these events occur: handling input events and WPF commanding.
The more basic of the two mechanisms, handling input events, involves attaching event handlers from the code-behind file directly to input events on UIElement
s and ContentElement
s. Event handling like this works for simple scenarios, but breaks down in MVVM applications. To understand how it breaks down, imagine a large data entry screen where clicking on any of several buttons or pressing the Enter key on any control causes the entire screen to save. In order to invoke the Save method on the screen's root view model object, we need to create an event handler for each type of input, such as Click
, MouseDown
, and PreviewKeyDown
. Each event handler must get a reference to the root view model object by down casting the DataContext
of the correct UIElement
or ContentElement
. Then the save logic can be invoked. This is definitely not data binding, so I'll move on to a way of handling input events that has more promise.
The other input mechanism, WPF commanding, implements the Command pattern. If you don't understand the Command pattern, I suggest that you read up on it, as it is a very valuable concept for UI development. WPF commanding implements the Command pattern by using elements in the logical hierarchy as command invokers, and other elements in the logical hierarchy act as command receivers. Commands that inherit from the RoutedCommand
type propagate up the logical hierarchy via RoutedEvent
s until a command receiver is found. The command receiver then invokes application logic through event handlers.
Any UIElement
or ContentElement
can act as a command invoker by simply adding an InputBinding
to its InputBindings
collection and mapping the binding to an input gesture and RoutedCommand
. When the input gesture is performed on the containing element, the RoutedCommand
is invoked. The InputBinding
class implements the interface ICommandSource
to indicate that it is a command invoker, although the interface is not necessary for commanding to work. Some built-in controls implement ICommandSource
directly to indicate that they can invoke a command when any one of many specific input events occurs. You can think of this as a shortcut to adding all the needed InputBinding
s. The Button
control is one example. A command can be attached directly to a Button
instance, and all mouse-clicks, space key presses, Enter key presses, etc., will invoke the command.
Not only can any UIElement
or ContentElement
act as a command source, but they can act as a command receiver by simply adding a CommandBinding
to the element's CommandBindings
collection. CommandBinding
s allow us to handle RoutedCommand
s and execute event handlers in the code-behind file. Despite the fact that CommandBinding
s still require us to use the code-behind file, there is a lot of value to be gained in using WPF commanding. It solves a lot of problems not necessarily related to our view model binding problem. To understand those advantages, I suggest you look at Josh Smith's blog post: Understanding Routed Commands.
So how can we bind user input events in our presentation layer to the methods of our view model?
Current Solutions
Most of the current solutions, such as Josh Smith's RelayCommand
and Prism's DelegateCommand
, take advantage of the fact that the command properties of some WPF controls allow the use of command types other than RoutedCommand
. The commands just need to implement the ICommand
interface. The suggested way to use the RelayCommand
s and DelegateCommand
s is to add command properties to the view model, map the commands to methods in the view model, and then bind the command properties of the view model to the command properties of the WPF controls.
Although this approach does use data binding, it has two major pitfalls. First, we can't bind our view model command properties to the command properties of InputBinding
s. This is because an InputBinding
does not inherit the DataContext
of its owner. There are approaches to getting around this that use static resources, but they are cumbersome.
The second problem with RelayCommand
s and DelegateCommand
s is that the truly valuable features of WPF commanding are not used; i.e., when using these classes, there is no separation between the command invoker and the command receiver. Some frameworks and applications attempt to deal with this issue by creating a hierarchical structure in their view models so that the Command pattern can be used within the view model. This approach is really just reinventing the wheel, and creates a lot of baggage for our view models.
There is, however, one current solution that works in conjunction with the WPF commanding architecture, and is pretty close to what we are looking for. That solution is Josh Smith's CommandSinkBinding
class. The class solves the major issues, but requires view model classes to implement a special interface. Through this interface, the view model must listen for commands it wants to handle. This seems to be a lot of baggage for the view model to deal with, and more importantly, this creates a dependency between the view model and WPF commands. Commands are a Windows presentation technology, and that is exactly the type of dependency that we should avoid in our view models. So what is a better solution?
My Solution
When we consider everything involved with using WPF commanding with the MVVM pattern, we realize that following the main stream solutions comes with too great of a trade-off and with too many limitations. In order for the two to work together, we really need for CommandBinding
s (not commands) to be bound to methods in the view model.
This, at first, seems simple enough. Just subclass the CommandBinding
type and create a custom implementation that calls methods on the DataContext
. Although the CommandBinding
class is not sealed and we can easily subclass it, Microsoft didn't give us the ability to override any of the behaviors associated with a CommandBinding
. In fact, most of the behaviors that we associate with a CommandBinding
actually exist in internal members of the RoutedCommand
class and in the sealed CommandManager
class. CommandBinding
s are really just markers for other inaccessible code to act upon. We simply have no way to extend the behavior. So it seems that to use RoutedCommand
s and a view model, we are forced to use event handlers. No binding allowed... that is unless you consider how RoutedCommand
s work using RoutedEvent
s.
Basically, a RoutedCommand
fires several RoutedEvent
s defined by the CommandManager
class for which the CommandManager
is listening (PreviewCanExecuteEvent
, PreviewExecutedEvent
, CanExecuteEvent
, ExecutedEvent
). While each RoutedEvent
propagates up or down the logical hierarchy, the CommandManager
is notified on each UIElement
and ContentElement
that the RoutedEvent
reaches. Each time the CommandManager
is notified, it inspects the current element's CommandBindings
collection, and if a CommandBinding
that is mapped to the RoutedCommand
is found, it executes the event handlers assigned to that CommandBinding
. The solution to our problem lies in the fact that we can essentially duplicate the behavior of the CommandBinding
and CommandManager
classes. We can just as easily listen to the WPF event system for RoutedCommand
events and look for our own custom CommandBinding
s. Our custom CommandBinding
s can then be used to execute methods of the DataContext
object rather than execute event handlers of the code-behind file.
RoutedCommandBinding
The custom CommandBinding
class that I have provided is aptly named RoutedCommandBinding
, and has methods that are executed when command events occur. A second class is responsible for listening to the WPF event system, and is named RoutedCommandMonitor
. This monitor class simply listens for WPF RoutedCommand
events, and calls the appropriate event handling methods on the appropriate RoutedCommandBinding
s. To understand the interaction between the two classes, take a look at the sequence diagram below. It shows how the CanExecuteEvent
event is handled:
The sequence is pretty straightforward. The only thing that is not necessarily obvious from the diagram is that the event argument is an instance of the CanExecuteRoutedEventArgs
class, and the RoutedCommandBinding
is responsible for setting its Handled
and CanExecute
properties. Here is how the RoutedCommandBinding
class looks:
public abstract class RoutedCommandBinding : CommandBinding
{
public bool ViewHandledEvents { get; set; }
public RoutedCommandBinding();
public RoutedCommandBinding(ICommand command);
protected internal abstract void OnPreviewCanExecute(
object sender, CanExecuteRoutedEventArgs e);
protected internal abstract void OnCanExecute(
object sender, CanExecuteRoutedEventArgs e);
protected internal abstract void OnPreviewExecuted(
object sender, ExecutedRoutedEventArgs e);
protected internal abstract void OnExecuted(
object sender, ExecutedRoutedEventArgs e);
}
The first thing you'll probably notice is that the class is declared abstract
and that all of the event handling methods are declared abstract
as well. This was done because the fundamental reason for creating the RoutedCommandBinding
class in the first place was that WPF's CommandBinding
implementation is not extensible. It would be short sighted to create a new implementation that cannot be extended. So now, any developer can come along and create a new version of the RoutedCommandBinding
class that does whatever they need. The custom RoutedCommandBinding
class can be simply added to the CommandBindings
collection of a UIElement
or ContentElement
, and it will work. Because the root problem is finding a way to execute command methods directly on the DataContext
, a concrete RoutedCommandBinding
implementation is needed. But before we get to it, we should look at how the RoutedCommandMonitor
class works.
RoutedCommandMonitor
The functionality of the RoutedCommandMonitor
class is possible because of a single method exposed by the WPF EventManager
class that allows us to listen to and handle RoutedEvent
s. The method, named RegisterClassHandler
, is the same method that WPF's CommandManager
class uses to handle RoutedCommand
events. The method's signature looks like this:
public static void RegisterClassHandler(
Type classType, RoutedEvent routedEvent,
Delegate handler, bool handledEventsToo);
All we need to do is register delegates for the RoutedCommand
events defined by the CommandManager
class, and our delegates will be invoked when any of those events occur. When notified, the RoutedCommandMonitor
simply looks for any RoutedCommandBinding
s in the CommandBindings
collection of the current element, and if one is found with a matching command, the correct method on the RoutedCommandBinding
is executed.
The implementation of this class had to overcome one major obstacle, and it centers on getting the collection of CommandBinding
s. Essentially, we cannot access the public CommandBindings
property of UIElement
s and ContentElement
s because the property is lazy loaded. If we did use the property, it wouldn't take long for the CommandBindings
collection of every UIElement
and ContentElement
in the entire application to become instantiated. That would be a major resource usage issue. The solution is to access the same internal method that the CommandManager
class uses to get the CommandBinding
s. The method is called GetCommandBindings
, and can only be accessed via Reflection, and Reflection is of course slow.
To get around this problem, we have to use a framework feature that a lot of .NET developers don't know about: open instance delegates (a.k.a. unbounded delegates). The reason so few know about the feature is it is only briefly mentioned on MSDN, and the performance gains over Reflection are never mentioned at all. However, there are some blog articles out there that describe how they work, such as Simon Cooper's recent one: Introduction to open instance delegates. I won't explain them here, but they are used internally by the RoutedCommandMonitor
class to execute the GetCommandBindings
method in a performant way. Problem solved!
DataContextCommandBinding
The class that actually contains the behavior that we need is called DataContextCommandBinding
, and it is simply an implementation of the RoutedCommandBinding
class that uses open instance delegates to execute methods on the DataContext
. The class looks like this:
public class DataContextCommandBinding : RoutedCommandBinding
{
public new string CanExecute { get; set; }
public new string Executed { get; set; }
public new string PreviewCanExecute { get; set; }
public new string PreviewExecuted { get; set; }
public DataContextCommandBinding() { };
public DataContextCommandBinding(ICommand command);
protected internal override void OnPreviewCanExecute(
object sender, CanExecuteRoutedEventArgs e);
protected internal override void OnCanExecute(
object sender, CanExecuteRoutedEventArgs e);
protected internal override void OnPreviewExecuted(
object sender, ExecutedRoutedEventArgs e);
protected internal override void OnExecuted(
object sender, ExecutedRoutedEventArgs e);
}
And a sample of its usage in XAML looks like this:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:cmd="clr-namespace:RoutedCommandBindingSample.Commands">
<Window.CommandBindings>
<cmd:DataContextCommandBinding
Command="ApplicationCommands.Close"
Executed="Close" CanExecute="CanClose" />
</Window.CommandBindings>
<Button Content="Close" Command="ApplicationCommands.Close"/>
</Window>
The interesting part about this class, other than how it executes methods on the DataContext
, is that the event declarations of the CommandBinding
class are overridden (not overloaded) with string properties that are used to store the names of the methods of the DataContext
to be executed. When the built-in WPF CommandManager
accesses DataContextCommandBinding
instances, it is as a CommandBinding
, thus the events defined by the CommandBinding
class are used. Those events will not have any handlers attached, and as a result, the CommandManager
does nothing with them. When the DataContextCommandBinding
accesses its own members, it uses the string properties. The events were overridden in this manner so that there is little difference between the semantics of instantiating a normal CommandBinding
and those of instantiating a DataContextCommandBinding
in XAML.
Once the RoutedCommandMonitor
executes any of the command methods of the DataContextCommandBinding
, the appropriate method is dynamically called on the DataContext
. The permitted method signatures for the command methods are shown below:
bool MyCanExecuteMethod();
bool MyCanExecuteMethod(object parameter);
void MyExecutedMethod();
void MyExecutedMethod(object parameter);
CommandExecutionManager
Internally, the DataContextCommandBinding
class uses another class to actually execute the methods of the DataContext
. It defers the dynamic execution logic, which is fairly complex, so that other classes and implementations of RoutedCommandBinding
can reuse it. The execution logic is complex because open instance delegates are used to invoke the methods of the DataContext
, and they are cached for performance reasons. With the CommandExecutionManager
class in the picture, we can now look at a full sequence diagram of a RoutedCommand
event being handled by a DataContext
object. Below is how the ExecutedEvent
event is handled:
Bonus: DataContextCommandAdapter
The classes that I have described show how to bind directly to the DataContext
from a CommandBinding
. But what if all you really want to do is execute a method on the view model directly from a button or an InputBinding
? Well, I have provided a markup extension that does just that and uses the CommandExecutionManager
to do so. The markup extension is named DataContextCommandAdapter
, and below is a sample of how it is used:
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:cmd="clr-namespace:RoutedCommandBindingSample.Commands">
<Button Content="Close"
Command="{cmd:DataContextCommandAdapter Close, CanClose}/>
</Window>
As you can see, it is simple enough to use, and its usage is very similar to the DataContextCommandBinding
, except the parameters are not named (this is a side effect of how arguments are supplied to markup extensions). The first argument is the name of the method that handles the Executed
event, and the second, optional argument, is the name of the method that handles the CanExecute
event. The methods can have the same signatures permitted by the DataContextCommandBinding
class. There is a major limitation for using this extension; it will not work if used on the Command
property of an InputBinding
when using the .NET 3.5 Framework. It will work fine though in the .NET 4.0 framework. Because of this, I have provided two sample solutions, one for VS 2010 with .NET 4.0, and the other for VS 2008 with .NET 3.5.
And that's it. The attached solution provides the code for the classes described here, as well as a simple media player application that exhibits their usage.
References
Revision History
- August 15, 2010 - Created the article.
- August 16, 2010 - Added illustration to introduction, and fixed typos.
- August 17, 2010 - Updated project to allow null
CanExecute
values to be provided.
- August 20, 2010 - Fixed minor typo.
- September 23, 2010 - Updated code to handle disconnected
DataContext
objects.
- March 10, 2011 - Applied additional fix related to disconnected
DataContext
objects.