#1,094 – Disabling Editing Operations in a TextBox

You can disable the cut/copy/paste features in a TextBox by handling the CommandManager.PreviewCanExecute event and checking for the associated editing commands.

TextBox has implicit command bindings to support cut, copy, and paste commands.  When the user executes one of these commands, using the context menu or a keyboard shortcut, the associated routed command is executed, with the TextBox as the source.  You can short-circuit the command by intercepting PreviewCanExecute and making sure that CanExecute returns false.

Markup:
        <TextBox Name="txtSomeText"
                 CommandManager.PreviewCanExecute="txtSomeText_PreviewCanExecute"
                 Width="220" Height="25" Margin="10"/>

Code-behind:

        private void txtSomeText_PreviewCanExecute(object sender, CanExecuteRoutedEventArgs e)
        {
            if ((e.Command == ApplicationCommands.Cut) ||
                (e.Command == ApplicationCommands.Copy) ||
                (e.Command == ApplicationCommands.Paste))
            {
                e.Handled = true;
                e.CanExecute = false;
            }
        }

The editing functions are now disabled. The context menu in the TextBox shows the commands greyed out and corresponding keyboard shortcuts do nothing.

1094-001

#1,093 – Intercepting a Command Before It Executes

When a command that is bound to an element executes, it executes some code.  The code is linked to the command as part of the command binding.  In some cases, you don’t have access to this code.  The TextBox control, for example, has built-in commands for cut/copy/paste features.

You can intercept a command that is about to be executed on an element by defining a handler for the PreviewExecuted event.

        <TextBox Name="txtSomeText"
                 CommandManager.PreviewExecuted="txtSomeText_PreviewExecuted"
                 Width="220" Height="25" Margin="10"/>

In the body of the PreviewExecuted handler, you can determine what command is being executed.  You can cancel the execution by setting the Handled property to true.  In the example below, we prohibit Paste functionality in the TextBox.

        private void txtSomeText_PreviewExecuted(object sender, ExecutedRoutedEventArgs e)
        {
            if (e.Command == ApplicationCommands.Paste)
            {
                e.Handled = true;
            }
        }

#1,092 – An Example of Using a CommandTarget

Setting the CommandTarget property allows an element executing a routed command to initiate the routing of a command with a different element.

In the example below, clicking on the Button initiates a Paste command, but the routed command originates with a TextBox rather than the button.  In this particular case, because a TextBox implicitly has a command binding for the Paste command, text currently in the paste buffer is automatically pasted into the TextBox.  No code-behind is required in order for this to work.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Commands" Width="320" Height="220">

    <StackPanel>
        <TextBox Name="txtSomeText"
                 Width="220" Height="25" Margin="10"/>
        <Button Content="Paste"
                Command="ApplicationCommands.Paste"
                CommandTarget="{Binding ElementName=txtSomeText}"
                Margin="10" Padding="10,3"
                HorizontalAlignment="Center" />
    </StackPanel>
</Window>

1092-001

#1,091 – Using a CommandTarget to Change the Source of a Routed Command

The source of a routed command is the element that is invoking the command.  The sender parameter in the Executed or CanExecute handlers is the object that owns the event handler.  Setting the Command parameter of a Button to a particular command and then binding the command to some code in the CommandBindings for a main Window, the button is the source and the window is the sender.

When setting the Command property, you can also set the CommandTarget property, indicating a different element that should be treated as the source of the routed command.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Commands" Width="320" Height="220">

    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Find"
                        CanExecute="Find_CanExecute"
                        Executed="Find_Executed"/>
    </Window.CommandBindings>

    <StackPanel>
        <TextBox Name="txtSomeText"
                 Width="140" Height="25" Margin="10"/>
        <Button Content="Find"
                Command="ApplicationCommands.Find"
                CommandTarget="{Binding ElementName=txtSomeText}"
                Margin="10" Padding="10,3"
                HorizontalAlignment="Center" />
    </StackPanel>
</Window>

The Find command now appears to originate from the TextBox.  We can see this in the event handler for the Executed event.

1091-001

 

#1,090 – Sender vs. Source in CommandBinding Event Handlers

When handling a command’s Executed or CanExecute events, you can check the ExecutedRoutedEventArgs.Source or CanExecuteRoutedEventArgs.Source properties to get at the control that is the originator of the event.  But the event handler also includes a sender parameter that in many cases also points to the originator of the event.

The difference is:

  • The Source property refers to the originator of the event
  • The sender parameter refers to the object that owns the event handler

In the example below, clicking on the Button initiates a Paste command, which is bound to code using the parent Window’s CommandBindings property.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Commands" Width="320" Height="220">

    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Paste"
                        CanExecute="Paste_CanExecute"
                        Executed="Paste_Executed"/>
    </Window.CommandBindings>

    <StackPanel>
        <Button Content="Paste"
                Command="ApplicationCommands.Paste"
                Margin="10" Padding="10,3"
                HorizontalAlignment="Center" />
    </StackPanel>
</Window>

The Button is the Source of the routed command and the main Window is the sender.

1090-001

#1,089 – Adding a Parameter to a Command

When you set the Command property of a user interface element, you’re binding that element to a particular command.  The command, in turn, is associated with some code through its Executed property.

You can specify a command parameter using the CommandParameter property.  The data in this property will be passed to the code that runs when the command executes.

The XAML fragment below shows two buttons that both bind to the same command, but pass in different data.

        <Button Content="Open A"
                Command="ApplicationCommands.Open"
                CommandParameter="File A"
                Margin="10" Padding="10,3"
                HorizontalAlignment="Center" />
        <Button Content="Open B"
                Command="ApplicationCommands.Open"
                CommandParameter="File B"
                Margin="10" Padding="10,3"
                HorizontalAlignment="Center" />

We can then read that parameter in the code bound to the command’s Executed property.

        public void Executed_Open(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show(string.Format("Executing Open command for [{0}]", e.Parameter));
        }

1089-001

#1,088 – Removing Key Bindings

You’ll sometimes discover that there are built-in key bindings that you want to get rid of.  If you define the KeyBinding shown below, you’ll discover that the Ctrl+Alt+O key sequence works to execute the Open command, as expected.  But the Ctrl+O sequence also appears to do the same thing.

    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Open"
                        Executed="Executed_Open"
                        CanExecute="CanExecute_Open"/>
    </Window.CommandBindings>
    <Window.InputBindings>
        <KeyBinding Command="ApplicationCommands.Open"
                    Gesture="Ctrl+Alt+O"/>
    </Window.InputBindings>

Ctrl+O is automatically defined as an existing key binding that binds to the ApplicationCommands.Open command.  You can remove it by binding Ctrl+O to the ApplicationCommands.NotACommand command.  Ctrl+O will no longer be associated with the Open command.

        <Window.InputBindings>
            <KeyBinding Command="ApplicationCommands.Open"
                        Gesture="Ctrl+Alt+O"/>
            <KeyBinding Command="ApplicationCommands.NotACommand"
                        Gesture="Ctrl+O"/>
        </Window.InputBindings>

#1,087 – Associating a Key Binding with Multiple Modifier Keys

You define a KeyBinding object to bind a key gesture (i.e. keypress) to a particular command.  You can do this in XAML by defining a <KeyBinding> element, associating a routed command with a key “gesture”.  The gesture indicates the key that you can press in order to execute the command.

Key gestures typically require associating a key with at least one of the modifier keys (Ctrl, Alt, Shift, or Windows key).  For example, Ctrl+O is specified as:

        <KeyBinding Command="ApplicationCommands.Open"
                    Gesture="Ctrl+O"/>

You can also combine modifier keys, using the “+” symbol.

        <KeyBinding Command="ApplicationCommands.Open"
                    Gesture="Ctrl+Alt+O"/>

#1,086 – Defining a Key Binding in XAML

You define a KeyBinding object to bind a key gesture (i.e. keypress) to a particular command.  You can do this in code by creating a KeyBinding instance and adding it to an UI elements InputBindings collection.

You can also define a key binding in XAML, as shown below.  You use a <KeyBinding> element for each key binding.

<Window x:Class="WpfApplication1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Title="Commands" Width="320" Height="220">

    <Window.CommandBindings>
        <CommandBinding Command="ApplicationCommands.Open"
                        Executed="Executed_Open"
                        CanExecute="CanExecute_Open"/>
    </Window.CommandBindings>
    <Window.InputBindings>
        <KeyBinding Command="ApplicationCommands.Open"
                    Gesture="Ctrl+O"/>
    </Window.InputBindings>

    <StackPanel/>
</Window>

Here is the code-behind, containing methods for Executed and CanExecute.

        public void Executed_Open(object sender, ExecutedRoutedEventArgs e)
        {
            MessageBox.Show("Executing the Open command");
        }

        public void CanExecute_Open(object sender, CanExecuteRoutedEventArgs e)
        {
            e.CanExecute = true;
        }

#1,085 – Input Bindings Don’t Require that Element Binds to Command

When binding a routed command in WPF to a user interface element, you typically do the following:

  • Create a CommandBinding instance that associates a command to executable code
  • Add the CommandBinding to the element’s CommandBindings collection (typically belonging to the top-level window)
  • Set the Command property of an individual user interface element to refer to the Command

When you define InputBindings, you must perform the first two steps listed above.  You do not have to set the Command property of any user interface element in order for the input binding to work.

Consider the following example:

  • We bind a command to some code by creating a CommandBinding
  • We add the CommandBinding to a window’s CommandBindings collection
  • We define a KeyBinding for the same command and add to window’s InputBindings

We can now execute the command using the key, even though we didn’t set the Command property for any UI element.