Click here to Skip to main content
Click here to Skip to main content

Executing Command Logic in a View Model

, 9 Mar 2011
Rate this:
Please Sign up or sign in to vote.
Introduces the RoutedCommandBinding class as a new way for invoking methods in a View Model directly from XAML in an MVVM application.

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:

  1. Command invoked by a Button
  2. Command received by a DataContextCommandBinding
  3. Command relayed to a method of the view model

RoutedCommandBindingSample4.png

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 UIElements and ContentElements. 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 RoutedEvents 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 InputBindings. 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. CommandBindings allow us to handle RoutedCommands and execute event handlers in the code-behind file. Despite the fact that CommandBindings 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 RelayCommands and DelegateCommands 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 InputBindings. 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 RelayCommands and DelegateCommands 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 CommandBindings (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. CommandBindings 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 RoutedCommands and a view model, we are forced to use event handlers. No binding allowed... that is unless you consider how RoutedCommands work using RoutedEvents.

Basically, a RoutedCommand fires several RoutedEvents 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 CommandBindings. Our custom CommandBindings 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 RoutedCommandBindings. To understand the interaction between the two classes, take a look at the sequence diagram below. It shows how the CanExecuteEvent event is handled:

RoutedCommandBinding1.png

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 RoutedEvents. 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 RoutedCommandBindings 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 CommandBindings. Essentially, we cannot access the public CommandBindings property of UIElements and ContentElements 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 CommandBindings. 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:

RoutedCommandBinding2.png

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.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Doug Schott
Software Developer Fidelity National Financial
United States United States
Doug Schott has been developing .NET applications for the past 8 years.
 
He is currently working as a senior software consultant at Fidelity National Financial.

Comments and Discussions

 
QuestionCommand Arguments PinmemberMember xxx12-May-14 23:38 
QuestionOwn commands with DataContextCommandBinding PinmemberMember 832348615-May-13 7:09 
AnswerRe: Own commands with DataContextCommandBinding PinmemberDoug Schott15-May-13 7:53 
GeneralRe: Own commands with DataContextCommandBinding PinmemberMember 832348615-May-13 8:25 
GeneralRe: Own commands with DataContextCommandBinding PinmemberDoug Schott15-May-13 13:55 
GeneralRe: Own commands with DataContextCommandBinding PinmemberMember 832348616-May-13 10:28 
GeneralRe: Own commands with DataContextCommandBinding PinmemberDoug Schott17-May-13 3:47 
GeneralRe: Own commands with DataContextCommandBinding PinmemberMember 832348619-May-13 2:16 
GeneralMy vote of 5 PinmemberVitaly Tomilov30-Jun-12 12:49 
Questionkeep CommandManager? Pinmemberstef89924-Apr-12 7:37 

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

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

| Advertise | Privacy | Mobile
Web04 | 2.8.140721.1 | Last Updated 9 Mar 2011
Article Copyright 2010 by Doug Schott
Everything else Copyright © CodeProject, 1999-2014
Terms of Service
Layout: fixed | fluid