Click here to Skip to main content
15,867,308 members
Articles / Desktop Programming / WPF

Executing Command Logic in a View Model

Rate me:
Please Sign up or sign in to vote.
4.94/5 (54 votes)
9 Mar 2011CPOL14 min read 302.8K   2.8K   142   81
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:

C#
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:

C#
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:

XML
<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:

C#
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:

XML
<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)


Written By
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

 
QuestionHow to raise CanExecuteChanged event Pin
Tim Calladene16-Oct-18 6:33
Tim Calladene16-Oct-18 6:33 
QuestionAfter some struggle we successfully added it to our Product Pin
tverrbjelke8-Aug-14 0:56
tverrbjelke8-Aug-14 0:56 
QuestionCommand Arguments Pin
Member xxx12-May-14 23:38
Member xxx12-May-14 23:38 
QuestionOwn commands with DataContextCommandBinding Pin
Member 832348615-May-13 7:09
Member 832348615-May-13 7:09 
AnswerRe: Own commands with DataContextCommandBinding Pin
Doug Schott15-May-13 7:53
Doug Schott15-May-13 7:53 
GeneralRe: Own commands with DataContextCommandBinding Pin
Member 832348615-May-13 8:25
Member 832348615-May-13 8:25 
GeneralRe: Own commands with DataContextCommandBinding Pin
Doug Schott15-May-13 13:55
Doug Schott15-May-13 13:55 
GeneralRe: Own commands with DataContextCommandBinding Pin
Member 832348616-May-13 10:28
Member 832348616-May-13 10:28 
GeneralRe: Own commands with DataContextCommandBinding Pin
Doug Schott17-May-13 3:47
Doug Schott17-May-13 3:47 
GeneralRe: Own commands with DataContextCommandBinding Pin
Member 832348619-May-13 2:16
Member 832348619-May-13 2:16 
GeneralMy vote of 5 Pin
Vitaly Tomilov30-Jun-12 12:49
Vitaly Tomilov30-Jun-12 12:49 
Questionkeep CommandManager? Pin
stef89924-Apr-12 7:37
stef89924-Apr-12 7:37 
SuggestionMark Bergan's TargetInvocationException catching Pin
Michele Bernardi2-Jan-12 7:15
Michele Bernardi2-Jan-12 7:15 
QuestionMulti Event Command Binder Pin
Member 432946918-Dec-11 7:20
Member 432946918-Dec-11 7:20 
BugDesigner throws a NullReferenceException when using DataContextCommandAdapter markup extension Pin
porcus19-Oct-11 5:33
porcus19-Oct-11 5:33 
GeneralRe: Designer throws a NullReferenceException when using DataContextCommandAdapter markup extension Pin
Doug Schott19-Oct-11 5:51
Doug Schott19-Oct-11 5:51 
Unfortunately, I've not tested the code in conjunction with the Xaml designer (I dislike using the designer because it tends to be glitchy)... That being said, you might want to take a look at the ProvideValue method of the DataContextCommandAdapter class. At design time the IProvideValueTarget service might be unavailable and I believe my code throws an exception if it is not available. You may try changing the behavior for this situation so that no exception is thrown. This is just a guess... let me know if you're successful.
SuggestionReaderWriterLockSlim use: slight improvement. Pin
spi2-Sep-11 3:06
professionalspi2-Sep-11 3:06 
GeneralRe: ReaderWriterLockSlim use: slight improvement. Pin
Doug Schott2-Sep-11 4:08
Doug Schott2-Sep-11 4:08 
SuggestionRe: ReaderWriterLockSlim use: slight improvement. Pin
spi8-Sep-11 21:30
professionalspi8-Sep-11 21:30 
GeneralRe: ReaderWriterLockSlim use: slight improvement. Pin
Doug Schott9-Sep-11 1:10
Doug Schott9-Sep-11 1:10 
GeneralMy vote of 5 Pin
Filip D'haene25-Aug-11 3:00
Filip D'haene25-Aug-11 3:00 
GeneralMainWindow.xaml getting Pin
trhughes7511-Aug-11 8:19
trhughes7511-Aug-11 8:19 
GeneralRe: MainWindow.xaml getting Pin
trhughes7512-Aug-11 5:10
trhughes7512-Aug-11 5:10 
SuggestionSimple semantics Pin
Andreas Hassmann3-Jul-11 9:47
professionalAndreas Hassmann3-Jul-11 9:47 
GeneralRe: Simple semantics Pin
Doug Schott4-Jul-11 1:31
Doug Schott4-Jul-11 1:31 

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.