The Command Pattern In Windows Presentation FoundationJelle Druyts
Applies to:
Windows Presentation Foundation (formerly codenamed "Avalon"), or WPF for short, is a brand new Microsoft framework for developing very rich and powerful Windows applications. It will ship as part of Windows Vista, the next major version of Windows that will be released in the coming months, but WPF will also be available on Windows XP SP2 and Windows Server 2003. There is much to be said about Windows Presentation Foundation and its numerous new and enhanced capabilities, but this article will in stead focus on an old trusted friend, who has finally been given a dedicated room in the big house of Windows User Interface development: the "Command" pattern. This design pattern basically abstracts all actions the user can perform in an application into the notion of "commands"; it has been implemented in many different ways on top of various UI frameworks, but now, it has finally made it into the gut of the system itself. Note that this article is based on a public preview of WPF, so it's possible that there are implementation details that will change over time as the product matures into completion. Contents: The Command Design PatternAccording to its original description in the famous "Design Patterns" book by the so-called Gang of Four, the Command pattern allows you to "encapsulate a request as an object, thereby letting you parameterize clients with different requests, queue or log requests, and support undoable operations". Because design patterns can, by definition, be applied to a whole range of different scenarios, this is a rather general description. Let's refine that definition in the WPF space as "an action that a user can perform through the keyboard or by interacting with a user interface element". If you look at a modern Graphical User Interface (GUI) application like Visual Studio, you can recognize "Open File", "Copy", "Paste", "Build Solution", "New Project", "Attach to Process" and many, many more as commands: they are all actions you perform by clicking a toolbar button or a menu item, or by pressing a keyboard shortcut.
![]() Commands In WPFNow, let's get our hands dirty and look at how commands are implemented in Windows Presentation Foundation.
public interface ICommand
{
// Methods.
void Execute(object parameter);
bool CanExecute(object parameter);
// Events.
event EventHandler CanExecuteChanged;
}The Execute method contains the logic to perform the action that makes up the command (e.g. make the selected text bold). The CanExecute method returns a value that determines if the command is currently valid (e.g. if there is any selected text). The CanExecuteChanged event is raised when the command notices that the value returned by the CanExecute method has changed (e.g. there is no more selected text). These last two members allow user interface elements to check if they should be enabled, and as we will see later on, WPF handles these automatically to gray them out. The parameter object on the two methods is just a generic way to pass any information into the command.
As you can see, there is no Unexecute method or any other built-in mechanism to support undoable operations in WPF, but you can handle the predefined Undo and Redo commands for your own purposes (like the TextBox class does now to support undo and redo for text editing). The RoutedCommand Class In WPF, there is currently only one class that implements this interface: the System.Windows.Input.RoutedCommand class. public class RoutedCommand : ICommand
{
// ICommand implementation.
void ICommand.Execute(object parameter);
bool ICommand.CanExecute(object parameter);
public event EventHandler CanExecuteChanged;
// Constructors.
public RoutedCommand();
public RoutedCommand(string name, Type ownerType);
public RoutedCommand(string name, Type ownerType, InputGestureCollection
inputGestures);
// Methods.
public void Execute(object parameter, IInputElement target);
public bool CanExecute(object parameter, IInputElement target);
// Properties.
public InputGestureCollection InputGestures { get; }
public bool IsBlockedByRM { get; set; }
public string Name { get; }
public Type OwnerType { get; }
}
Apart from implementing the ICommand interface, it defines a number of constructors, methods and properties to provide the actual baseline functionality of a command. As you can see, each command has a Name (e.g. "Copy"), an OwnerType (containing the type that defines the command), an IsBlockedByRM flag (which indicates if the command is disabled due to a Digital Rights Management policy, e.g. a copy protection) and a collection of InputGestures (which specify mouse or keyboard combinations such as CTRL-C, which are one of many ways the command can be invoked).
The "routed" part of the class name comes from the fact that many event-like behaviors in WPF are described as routed. With regular events in .NET, an event is ignored completely when there are no registered event handlers. This means you have to subscribe to all events of all objects you are potentially interested in. For large UI applications with lots of controls, this could mean you'd have to subscribe to tens or hundreds of events. To make it easier to handle events centrally – even though they could have initiated anywhere in the huge visual tree that makes up a UI application – WPF introduces the notion of routed events. This means that if an event isn't handled on the element that defined it, it bubbles up the visual tree until it reaches the root element. (Tunneling events also exist, which travel from the root element down to the initiating element, but this is outside the scope of this article.) The same bubbling mechanism applies to the RoutedCommand: if no handler is found to deal with the command, it travels up the visual tree until it is handled. The RoutedUICommand Class There is one specialized subclass of this RoutedCommand class, the RoutedUICommand class, which adds nothing but a Text property to provide a localized description of the command so it can be displayed in the UI of the application (e.g. as a button's tooltip): public class RoutedUICommand : RoutedCommand
{
// Constructors.
public RoutedUICommand();
public RoutedUICommand(string text, string name, Type ownerType);
public RoutedUICommand(string text, string name, Type ownerType,
InputGestureCollection inputGestures);
// Properties.
public string Text { get; set; }
}Since WPF is a UI framework, most commands will in fact be instances of this RoutedUICommand.
Built-in Commands There are currently 156 predefined commands in WPF to support the most common scenarios. These are all RoutedUICommands, grouped as static properties on 5 different classes.
Because these commands are predefined and well-known throughout the WPF framework itself, a lot of these will be handled automatically by the controls that ship with the framework. The TextBox control, for example, knows how to handle the Cut, Copy and Paste commands. Custom Commands Of course, while these built-in commands already provide an extensive set of commonly used functionality, you will probably want to define commands specific to your application as well. Fortunately, defining a custom command is very straightforward if you follow the pattern of the predefined commands: just create a new instance of a RoutedCommand or a RoutedUICommand (depending on whether the command will be "visible" on a UI or not) and make this available through a static property or field on the class that defines the command. Imagine, for example, a Customer window that needs to define a command to add a new customer: public partial class CustomerWindow : Window
{
public readonly static RoutedUICommand AddCustomerCommand;
static CustomerWindow()
{
AddCustomerCommand = new RoutedUICommand("Add Customer...",
"AddCustomerCommand", typeof(CustomerWindow));
AddCustomerCommand.InputGestures.Add(new KeyGesture(Key.C, ModifierKeys.Alt));
}
}As you can see, we expose a static singleton instance of a RoutedUICommand called AddCustomerCommand, and we initialize it in the static constructor to have a UI Text "Add Customer...", a Name that's the same as the field name, and the OwnerType will be set to the defining type, i.e. the CustomerControl type.
Furthermore, we add a KeyGesture to the command's InputGestures to indicate that the command can be executed by pressing the Alt-C shortcut. ![]() Executing CommandsNow that we've seen which commands are available out-of-the-box and how commands are defined, let's see how we can execute a command.
public partial class CustomerWindow : Window
{
public CustomerWindow()
{
InitializeComponent();
this.InputBindings.Add(new InputBinding(ApplicationCommands.Copy,
new KeyGesture(Key.F6, ModifierKeys.Control)));
}
}Pressing CTRL-C, CTRL-INS or CTRL-F6 in this window will now all execute the Copy command.
Calling The Execute Method You can also invoke a command through code, by calling the Execute method defined on the RoutedCommand class. Suppose that we have a button on our Customer window named AddCustomerButton, defined in XAML as follows: <Button Click="AddCustomerButtonClicked">Add Customer...</Button>We could then write the following code in its event handler to invoke the AddCustomerCommand: void AddCustomerButtonClicked(object sender, EventArgs e)
{
AddCustomerCommand.Execute(null, (IInputElement)sender);
}As you may recall from the RoutedCommand definition above, the first argument is the command parameter (any optional parameter you want to pass along), the second is the target of the routed command, i.e. the UI element where the bubbling starts. This can be important because commands can be handled at different places in the UI tree, as we will see later on. If you don't provide a target, the UI element that currently has the keyboard focus will be used as the command target.
Alternatively, if you don't have a reference to a RoutedCommand but to an ICommand in stead, you can call its Execute method as well. The difference is that it doesn't have the second argument to define the target element, but if it's a RoutedCommand (and it probably is, since WPF doesn't provide any other implementation of the ICommand interface), the UI element with the focus will again be used as the target. void AddCustomerButtonClicked(object sender, EventArgs e)
{
ICommand cmd = AddCustomerCommand;
cmd.Execute(null);
}Using The Command PropertyOf course, executing a command when a button or menu item is clicked is a very common scenario, so WPF provides a Command property on these UI elements that eliminates the code above: <Button Command="Copy">Copy</Button>This will simply execute the ApplicationCommands.Copy command when the button is clicked. Because "Copy" is a well-known predefined command, it's enough to just use its short name. If you want to use custom commands, you'll have to specify the XML namespace prefix and the class name as well: <Button Command="local:CustomerWindow.AddCustomerCommand">Add Customer...</Button>For this to work, you will need to make this "local" XML namespace prefix refer to the current project's CLR namespace. This can be done through the standard XAML mechanism of adding a Mapping Processing Instruction (PI) to the top of your XAML file, and a namespace mapping on the Window tag. The complete XAML for the Customer window can now look as follows: <?Mapping XmlNamespace="local" ClrNamespace="CustomControls" ?>
<Window x:Class="CustomControls.CustomerWindow"
xmlns="http://schemas.microsoft.com/winfx/avalon/2005"
xmlns:x="http://schemas.microsoft.com/winfx/xaml/2005"
xmlns:local="local"
Title="Customer Properties"
>
<StackPanel>
<Button Command="local:CustomerWindow.AddCustomerCommand">
Add Customer...
</Button>
</StackPanel>
</Window>This way, when the button is clicked, the AddCustomerCommand of the CustomerControl class in the CustomControls namespace will be executed. Optionally, in case this class is defined in another assembly, you can specify its name in the Assembly attribute of the Mapping PI.
This Command property is defined on the System.Windows.Controls.Primitives.ButtonBase class, so all its descendants like Button, RadioButton and CheckBox can directly use it. It's also present on the System.Windows.Controls.Primitives.MenuItem class so the same applies for menu items. And finally, the System.Windows.Documents.Hyperlink class also supports the property so you can also invoke commands from hyperlinks. Besides the Command property, these types also define CommandParameter and CommandTarget properties, which allow you to set the Execute method's parameter and target arguments, respectively. ![]() Handling CommandsNow that we know how commands are defined and how they can be executed, let's switch over to the consumer side and see how commands can be handled when they are invoked.
public class CommandBinding
{
// Events.
public event CanExecuteRoutedEventHandler CanExecute;
public event ExecutedRoutedEventHandler Executed;
public event CanExecuteRoutedEventHandler PreviewCanExecute;
public event ExecutedRoutedEventHandler PreviewExecuted;
// Methods.
public CommandBinding();
public CommandBinding(ICommand command);
public CommandBinding(ICommand command,ExecutedRoutedEventHandler executed);
public CommandBinding(ICommand command,ExecutedRoutedEventHandler executed,
CanExecuteRoutedEventHandler canExecute);
// Properties.
public ICommand Command { get; set; }
}A command binding basically keeps track of a command, and provides four routed events that allow you to preview or handle the invocation of the event (PreviewExecuted and Executed, respectively), and that provide a means for you to indicate if the command can currently execute (PreviewCanExecute and CanExecute, respectively).
You can add command bindings to any UIElement or ContentElement in WPF through their CommandBindings property as such: public partial class CustomerWindow : Window
{
public CustomerWindow()
{
InitializeComponent();
CommandBinding binding = new CommandBinding(ApplicationCommands.Copy);
binding.Executed += new ExecutedRoutedEventHandler(this.copy_Executed);
this.CommandBindings.Add(binding);
}
void copy_Executed(object sender, RoutedEventArgs e)
{
MessageBox.Show("Executed the Copy command");
}
} This will add an event handler to the Copy command to display a message box,
Alternatively, you can declare command bindings in XAML through the standard Property-Element syntax:
<Window ...>
<Window.CommandBindings>
<CommandBinding Command="Copy" Executed="copy_Executed" />
</Window.CommandBindings>
</Window>It's important to note that if there are no command bindings for a certain command, then the command will effectively be disabled. This makes sense, because there is no point in clicking a button if there is no code behind it to execute.
Handling The Executed Event As you've seen, the CommandBinding class defines a number of events, the most important one being the Executed event. An event handler for this event (and for its preview event as well) must take a sender of type object as its first argument (following the standard event pattern in .NET) and an event arguments object of type System.Windows.Input.ExecutedRoutedEventArgs.The sender object will always be the control defining the command bindings, not the control that triggered the command. If a button on a window has its Command property set, for example, and the window itself has defined the command binding for that command (like in the example above), the sender would be the window instance, not the button.The ExecutedRoutedEventArgs that is passed into the event handler contains more useful information, especially if you need to know which control triggered the command. It inherits from the standard WPF RoutedEventArgs class to provide an additional Command and Parameter property, so its public interface looks like the following: public sealed class ExecutedRoutedEventArgs
{
// Properties
public object OriginalSource { get; }
public object Source { get; set; }
public bool Handled { get; set; }
public RoutedEvent RoutedEvent { get; set; }
public ICommand Command { get; }
public object Parameter { get; }
}The read-only OriginalSource property contains the control that triggered the event, so this will contain the button that was clicked, for example. The read-write Source property contains the same control at first, but can be replaced at will to hide a low-level UI element within a composite control, for example.
The Handled flag can be used to indicate if the command was handled. This can be used to stop the command from bubbling up the visual tree when it has already been dealt with. When you press CTRL-C in a TextBox that has some selected text, for example, the text will be copied to the clipboard and the event will be marked as handled so it won't surface beyond the TextBox. If no text was selected, nothing could be done by the TextBox so the event will bubble further up the visual tree. The last two properties allow you to retrieve some information about the command being executed. The Command property contains the command instance that was executed and whose event is now being routed. The Parameter property contains the optional parameter that was passed into the command when it was executed (through the Execute call or the CommandParameter property of a Button, for example). ![]() Enabling CommandsAs mentioned above, if there are no command bindings for a certain command, then the command will effectively be disabled. Apart from not executing any command that isn't enabled, WPF will automatically disable the well-known UI elements that are bound to a command that isn't enabled. That means that all controls that have a Command property as mentioned above (including menu items and buttons), will automatically reflect the fact that the command is enabled or not. This is an important feature because it means you don't need to manage any part of the user interface yourself when dealing with disabled commands.
void addCustomer_CanExecute( object sender, CanExecuteRoutedEventArgs e )
{
if( accountManagersList.SelectedIndex < 0 )
{
e.CanExecute = false;
}
else
{
e.CanExecute = true;
}
}It's important to note that if the CanExecute event isn't handled (i.e. there are no event handlers attached to it), the command will always be enabled. As soon as there's at least one event handler, they should all return true to enable the command. So the vote is actually a veto right, allowing you to suppress any command by a single "no".
![]() Wrapping UpAs you've seen, there is extensive support for the Command pattern in Windows Presentation Foundation, making it easy to separate the implementation of a command from all the UI elements that provide access to it. Furthermore, with built-in support for disabling these UI elements that are bound to commands that are currently unavailable, WPF will make sure your application's look and feel is consistent, clear and professional.
![]() About the author
| ||||||