Tag Archives: CommandBinding

Commands, targets and bindings

In the last post, we saw how to use some built-in WPF Commands to implement behaviour such as cut, copy and paste in TextBoxes. In that example, most of the functionality is already coded into the TextBox control for us, so we had very little work to do. To use Commands in any more complex situation, we need to understand a bit more about how they work.

There are four main components needed in the implementation of a Command. First, there is the Command itself. A Command object contains some basic information to be associated with the command that it will ultimately run, such as any input gestures (keyboard shortcuts or mouse actions, usually) associated with the Command. All the 144 built-in Commands provided by WPF are objects of this type. Some, such as copy, have some input gestures (Control+C for copy) pre-defined, while others do not. For now, we’ll consider only these given Command objects, and consider custom-made Commands later on.

Second, a Command needs a source, which is the object that generates the command. A command source is usually some UI element such as a Button or MenuItem. For example, a Button can be pressed to initiate a copy action.

Third, we need a target, which is an object on which the Command will act. In the case of the copy action, the target must be some control that contains something we can copy, such as text in a TextBox.

Finally, the guts of a Command are contained in a CommandBinding. A CommandBinding contains the event handlers that are called when the command is run, or when we need to check if a command is able to be run. Each UI control has a collection of CommandBindings, so that more than one Command can be associated with a given control. Conversely, we can also associate one Command with more than one control (as with the copy command being associated with both a toolbar button and a menu item).

Here’s a reminder of the interface we used in the last post:

Returning to our simple example from the last post, we saw there that all we did was attach a Command object to each Button and MenuItem. We didn’t specify any command targets or command bindings, so how did the program know what to do?

The answer comes in two parts. First, if no target is specified for a Command, the control that last had the keyboard focus before the Command was invoked is taken as the target. To see this, select some text (e.g. from Notepad) into the clipboard before starting up the program. When the program starts, none of its controls has the keyboard focus and you’ll see that the Paste button and menu item are disabled, even though there is something on the clipboard that could be pasted. When you click in either TextBox, the Paste button becomes enabled, since that TextBox has now become the Command target for the Paste command.

The CommandBindings for paste, cut and copy are pre-written when the target is a TextBox, so we don’t need to worry about them. With other Commands, things aren’t quite so simple.

To see how the other bits of a Command work, we’ll do some experiments with the Find button. Although the Find command is one of WPF’s built-in Commands, it doesn’t have pre-written bindings, so we need to do some work ourselves. For simplicity, we’ll work entirely in the C# code file. In the MainWindow() constructor, we’ll add the following at the end:

      findButton.Command = ApplicationCommands.Find;
      //findButton.CommandTarget = textBox1;
      CommandBinding binding = new CommandBinding(ApplicationCommands.Find);
      binding.Executed += new ExecutedRoutedEventHandler(binding_Executed);
      //findButton.CommandBindings.Add(binding);
      //textBox1.CommandBindings.Add(binding);

We’ve assigned the Find command to findButton. Ignoring the commented lines (we’ll use them later), we next create a CommandBinding associated with Find. We then provide a handler for the Executed event, which is run when the command is executed. For now, we don’t add this binding to any control, so it isn’t actually used yet.

The handler looks like this:

    void binding_Executed(object sender, ExecutedRoutedEventArgs e)
    {
      MessageBox.Show("Find dialog");
    }

All it does is display a MessageBox.

Now, according to what we’ve just said, since we haven’t specified a command target for Find, it should use whatever has the keyboard focus when findButton is pressed. If you run the program and select a TextBox, you’ll see that Find remains disabled. Why does this happen? After all, with Paste, the button became enabled as soon as we selected a TextBox.

The reason is that a TextBox has no built-in binding for Find, so even though the selected TextBox is being used as the command target, the lack of a binding means there are no instructions for Find to follow when it is invoked on the TextBox, so nothing can happen. As a result, the program won’t let you do anything that would try to invoke Find, and the button is disabled.

Next, try uncommenting the line:

textBox1.CommandBindings.Add(binding);

Now when we run the program, Find is disabled initially, but if we click in textBox1, it becomes enabled, and clicking on it brings up the MessageBox. However, it is only this TextBox that enables Find: clicking in textBox2 disables it again. This is because it is only textBox1 that has a binding for Find, so only it knows what to do when Find is invoked.

Next, try commenting out this line again, and uncommenting the binding to findButton, so the last two lines above become:

      findButton.CommandBindings.Add(binding);
      //textBox1.CommandBindings.Add(binding);

Now we find the Find button is enabled right from the start; we don’t need to click in either TextBox. This is because the Find button itself now knows how to handle the Find command, so it doesn’t need to rely on an implicit target in the form of a TextBox having the keyboard focus. In effect, findButton becomes its own target.

WPF is actually quite intelligent in being able to figure out when a control can handle a Command. If you now comment out the line beginning binding.Executed, for example, so that no handler is specified for the Executed event, the Find button will again be disabled even though a CommandBinding has been attached to findButton.

For our final experiment, use the following comment pattern in the above code:

      findButton.Command = ApplicationCommands.Find;
      findButton.CommandTarget = textBox1;
      CommandBinding binding = new CommandBinding(ApplicationCommands.Find);
      binding.Executed += new ExecutedRoutedEventHandler(binding_Executed);
      findButton.CommandBindings.Add(binding);
      //textBox1.CommandBindings.Add(binding);

We’ve now specified the target of findButton to be textBox1, but we’ve attached the binding to findButton. Now nothing you do can enable the Find button, since its target doesn’t know how to handle the Find command. Uncommenting the last line as follows again enables the Find button right from the start:

      findButton.Command = ApplicationCommands.Find;
      findButton.CommandTarget = textBox1;
      CommandBinding binding = new CommandBinding(ApplicationCommands.Find);
      binding.Executed += new ExecutedRoutedEventHandler(binding_Executed);
      //findButton.CommandBindings.Add(binding);
      textBox1.CommandBindings.Add(binding);

This might surprise you, since you might think that you’d need to give textBox1 the keyboard focus in order to enable the Find button. However, what has happened is that an explicit target has been given, and that target has a binding for the Find command attached, so the button is enabled at all times. It is only when no target has been set explicitly that the keyboard focus is used to select which target applies.

As you can see, knowing when a Command is enabled can be a bit tricky. Things get even worse when we consider enabling and disabling commands in the code, but we’ll look at that in the next post.

Code for this post is available here (but ignore the bits on custom commands, which will be covered later).

Advertisements