Command binding in WPF: global commands

The design of the WPF API encourages one to keep one’s code decoupled. That is, the goal is for each piece of code to do one thing,  do that one thing well, and to not carry dependencies on other pieces of code (particularly with respect to avoiding a provider being dependent on, or even aware of in any specific way, the code using that provider). This philosophy carries through to the way that WPF handles user input. While it’s certainly possible in WPF to simply wire event handlers to control events like Click, to have the associated handler perform the appropriate action for that control, there are higher level mechanisms that abstract the concepts of the source of user input, the action that user input corresponds to, and the piece of code responsible for handling that action.

The “action” is represented by the ICommand interface, and there are two main variations on that theme: the RoutedCommand and especially its subclass RoutedUICommand (both of which implement ICommand), and the directly-implemented ICommand. The former is typically used for commands that are specifically related to how the user interacts with the program itself (i.e. the UI), while the latter is typically used for interactions with the underlying data (i.e. implements the business logic in a view model). While the directly-implemented ICommand is just that — an implementation that is invoked directly through the ICommand object — the RoutedCommand represents the abstraction of a command, with the implementation of the command being bound to the command after the fact. Indeed, through the routing system, the same command can take on different concrete meaning depending on context; the command binding can vary according to the specific needs of the program, allowing for different implementations of the same command according to those needs.

Naturally, for a given command, the implementation should hold to the spirit of the intent behind the command; for example, if the command is named “open”, the implementation should involve opening something, not saving or closing it. WPF has a whole collection of pre-defined commands that a program can use, found in the ApplicationCommands class. For commonly used commands, this is a good place to look. If the action you’re implementing is found there, then you can use that instead of having to implement your own.

By now, you might be asking yourself why I’m writing all this. After all, WPF has been around for a long time now and no doubt there are plenty of other tutorials out there that adequately or even skillfully explain how command binding works. Indeed, as a non-expert in the WPF API, I’m unlikely to provide better or more detailed information than the experts who have written such tutorials. My motivation here is two-fold: first, as I mentioned in an earlier post it’s my hope that as a relative newcomer to the WPF API, I’ll be able to remember what was especially hard and present the information in an easy-to-digest manner; and second, as it happens I recently ran into a particular issue involving command binding, which required some time on my part investigating various options available in WPF, to learn what was possible and (I hoped) what was the best solution.

(By the way, I will admit that one of the things I found, and continue to find, so challenging about WPF is that it’s a very broad and complex API, often with several different ways to accomplish the same basic goal. At times, it almost feels like there were multiple people all designing solutions for similar or identical problems, and all of their solutions wound up in the API. Not only is this often disorienting — it’s easy to get confused about what particular paradigm one is actually using at the moment — it makes it very difficult to know whether one is solving a problem the right way. In some cases, a detailed investigation will reveal some truths. At other times, absent expert advice one just has to take on faith that “it works” is good enough 🙂 .)

The particular issue I was dealing with was this: I have an action in my program that allows the user to perform some configuration that affects the program globally. I have a single static method in the App class that when called, shows the UI for this configuration. I want the user to be able to do this in multiple windows, so I will be using the same command in each window. The simplest approach is simply to create a new command binding in each window, and have the code-behind call the static method:

<App.Resources>
  <RoutedUICommand x:Key="globalConfigCommand" Text="Configure Foo...">
    <RoutedUICommand.InputGestures>
      <KeyGesture>Ctrl+F</KeyGesture>
    </RoutedUICommand.InputGestures>
  </RoutedUICommand>
</App.Resources>

<Window.CommandBindings>
  <CommandBinding Command="{StaticResource globalConfigCommand}" Executed="GlobalConfigCommand_Executed"/>
</Window.CommandBindings>

I haven’t shown the GlobalConfigCommand_Executed() method. This is just the Executed event handler, which does nothing more than call the actual global command method.

Okay, so that doesn’t seem so hard. What so wrong with just binding the command in each window or other XAML element where it applies? Well, I see two issues, each of which are variations on the same theme:

  1. Extra typing. Well, that’s annoying enough, but what’s really a problem here is the violation of the “DRY” principle: Don’t Repeat Yourself. Having to duplicate the command binding each time is not just time-consuming but also creates a maintenance problem if the binding or, more likely, the attached event handler(s) have to change.
  2. For commands like this, where there’s a static (or possibly singleton) implementation shared by all applicable contexts, it seems silly enough to have to wrap the call to the shared implementation in a bare-bones event handler, but to have create such a wrapper in each context is even worse.

In my particular example, the cost of repeating oneself is not great. It’s just one command, and I might only have a handful of windows where I want it available. But it’s not hard to see that as the number of globally applicable commands goes up, the cost of repeating oneself increases as well. This is why it’s a good idea to design the code in a non-repetitive, reusable way, even if at the moment it seems okay to repeat oneself. If it was worth doing once, you’re probably going to need to do it again, and making sure you can do so in an efficient, maintainable way is a good goal to have.

Fortunately, WPF provides a mechanism to allow command bindings to be set up globally, rather than just for specific elements via the CommandBindings collection. The CommandManager class includes the RegisterClassCommandBinding() method for this purpose: using it, you can bind Execute and CanExecute event handlers for a command just as you would for an individual element, except for any class. This means that the command routing system, when searching for a handler for a RoutedCommand, will find the handler on any instance of the registered class, without requiring that the binding be declared for each instance.

Here’s an example of how one might use that:

App.xaml:

<Application.Resources>
  <RoutedUICommand x:Key="globalCommand" Text="Execute GlobalCommand">
    <RoutedUICommand.InputGestures>
      <KeyGesture>Ctrl+F</KeyGesture>
    </RoutedUICommand.InputGestures>
  </RoutedUICommand>
  <CommandBinding x:Key="globalCommandBinding"
      Command="{StaticResource globalCommand}"
      Executed="GlobalCommandBinding_Executed"/>
</Application.Resources>

App.xaml.cs:

public App()
{
    this.Startup += (sender, e) =>
    {
        CommandBinding globalCommandBinding = (CommandBinding)FindResource("globalCommandBinding");
        CommandManager
            .RegisterClassCommandBinding(typeof(Window), globalCommandBinding);
    };
}

private void GlobalCommandBinding_Executed(object sender, ExecutedRoutedEventArgs e)
{
    GlobalCommand(e.Parameter);
}

The above includes the following:

  1. The command itself, declared in the App’s resources. It can be referenced by any XAML in the project (e.g. in a MenuItem) through the usual {StaticResource globalCommand} syntax. Note: the command includes a key gesture; this will be available globally (via the same command registration shown here), whether or not any other XAML in the project actually uses the command.
  2. A command binding, which references the command, and binds it to an event handler in the App class, a method named GlobalCommandBinding_Executed().
  3. Code in a handler for the Startup event to register the command binding for the Window class. This has to happen in the Startup event rather than the constructor itself, because the App class’s XAML (and thus the "globalCommandBinding" resource) won’t be loaded and available until then.
  4. Finally, of course, is the Executed event handler bound by the command binding, which does nothing more than call the actual global command method.

With that all set up, now the command is available in every window of the program, without having to actually add anything to the window’s XAML. If the user presses the key gesture Ctrl+F, the command will execute. A MenuItem can reference the command from any XAML (global resource, XAML element in a UserControl, in a Window, etc.), and the item will show the command text and key gesture information, as expected, and will execute the bound handler when clicked.

There is still one thing about the above that’s a little annoying: following that exact pattern, one would need to write two statements in the Startup event handler code for each command binding: one to retrieve the resource, and then another to register the binding. We can definitely do a little better; one option would be to loop on an array of resource names (defined e.g. in an array) and call a helper method for each name. But it’s unlikely a CommandBinding object would be in the App class resources for any purpose other than a global binding. So why not just enumerate all of the CommandBinding object’s and register them all? That would look like this:

public App()
{
    this.Startup += (sender, e) =>
    {
        _RegisterCommandBindings(Resources);
    };
}

private static void _RegisterCommandBindings(ResourceDictionary resources)
{
    foreach (CommandBinding commandBinding in resources.Values.OfType<CommandBinding>())
    {
        CommandManager.RegisterClassCommandBinding(typeof(Window), commandBinding);
    }
}

There. Now, to add any new global command, we need only add to the App‘s XAML the command object itself, an Executed event handler in the code-behind, and of course the CommandBinding object to tie the two together. XAML for specific program elements need not be visited at all, unless one wants the command to be visible in some UI element.

As I mentioned earlier, I tried a number of different techniques. The above is what I feel works best, at least for me (but I hope for you too). But this is WPF and so there are other ways to accomplish the same effect, or at least something similar. It’s my plan to share in my next post the other techniques I tried; knowing the other options will, I think, provide some insight by comparison as to why I like the above the best, and will in any case give the reader alternatives if the above does not in fact seem best to them.

Leave a Reply

Your email address will not be published. Required fields are marked *


*