wpftextboxrouted-commands

WPF TextBox allow keybinding Undo to bubble


I'm handling key bindings in our application by allowing the key binding events to bubble up to the main window view where keybindings are defined in xaml and handled in the main window view model, e.g.,

 <Window.InputBindings>
    <KeyBinding Key="Left" Modifiers="Alt" Command="{Binding NavigateBackCommand}"/>
    <KeyBinding Key="Right" Modifiers="Alt" Command="{Binding NavigateForwardCommand}"/>
    <KeyBinding Key="c" Modifiers="Control" Command="{Binding CopyCommand}"/>
    <KeyBinding Key="v" Modifiers="Control" Command="{Binding PasteCommand}"/>
    <KeyBinding Key="d" Modifiers="Control" Command="{Binding DuplicateCommand}"/>
    <KeyBinding Key="n" Modifiers="Control" Command="{Binding AddCommand}"/>
    <KeyBinding Key="i" Modifiers="Control" Command="{Binding ImportCommand}"/>
    <KeyBinding Key="e" Modifiers="Control" Command="{Binding ExportCommand}"/>
    <KeyBinding Key="a" Modifiers="Control" Command="{Binding SelectAllCommand}"/>
    <KeyBinding Key="k" Modifiers="Control" Command="{Binding DeselectCommand}"/>
    <KeyBinding Key="z" Modifiers="Control" Command="{Binding UndoCommand}"/>
    <KeyBinding Key="y" Modifiers="Control" Command="{Binding RedoCommand}"/>
    <KeyBinding Key="z" Modifiers="Control+Shift" Command="{Binding RedoCommand}"/>
    <KeyBinding Key="F5" Command="{Binding RefreshCommand}"/>
    <KeyBinding Key="Delete" Command="{Binding DeleteCommand}"/>
    <KeyBinding Key="Escape" Command="{Binding EscapeCommand}"/>
</Window.InputBindings> 

This works well except for the TextBox control where the undo event ("Ctrl+Z") never appears to bubble up to the main window. I have set IsUndoEnabled on the TextBox to false, but it still doesn't appear to bubble. It's almost as if the TextBox is handling the event thereby preventing it bubbling all the way up.

I have spiked a fix using the below in a custom TextBox (MyTextBox), i.e., listen for the CommandBinding in the control and when hit look for the KeyBinding in the window and execute the associated command

public MyTextBox()
{
    IsUndoEnabled = false;

    CommandBindings.Add(new CommandBinding(
        ApplicationCommands.Undo,
        ((sender, args) =>
        {
            var window = Window.GetWindow(this);

            foreach (var keyBinding in window.InputBindings.OfType<KeyBinding>())
            {
                if (keyBinding.Key == Key.Y && keyBinding.Modifiers == ModifierKeys.Control)
                {
                    keyBinding.Command.Execute(null);
                }
            }
        })));
 }

but this seems very hacky. Is there away to disable a TextBox's built-in undo command and rather allow the key binding to bubble up so I can handle it?


Solution

  • It's almost as if the TextBox is handling the event thereby preventing it bubbling all the way up.

    That's precisely what it does.

    Is there away to disable a TextBox's built-in undo command and rather allow the key binding to bubble up so I can handle it?

    Not without implement some kind of "hack" like you have already done. Your solution of creating a custom TextBox to handle this is actually a good solution in my opinion.

    I am afraid there is no property or similar that you can just set to get the behaviour that you want, i.e. that the TextBox allows the event to bubble up without any custom implementation.