WPF TextBox拦截RoutedUICommands

Jos*_*ant 11 wpf keyboard-shortcuts undo routed-commands

我试图在我的WPF应用程序中使用Undo/Redo键盘快捷键(我使用命令模式实现了自己的自定义功能).但是,似乎TextBox控件正在拦截我的"撤消"RoutedUICommand.

什么是禁用此功能的最简单方法,以便我可以在UI树的根目录中捕获Ctrl + Z?TextBox如果可能的话,我想避免在我的应用程序中添加大量代码/ XAML .

以下简要说明问题:

<Window x:Class="InputBindingSample.Window1"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:loc="clr-namespace:InputBindingSample"
    Title="Window1" Height="300" Width="300">
    <Window.CommandBindings>
        <CommandBinding Command="loc:Window1.MyUndo" Executed="MyUndo_Executed" />
    </Window.CommandBindings>
    <DockPanel LastChildFill="True">
        <StackPanel>
            <Button Content="Ctrl+Z Works If Focus Is Here" />
            <TextBox Text="Ctrl+Z Doesn't Work If Focus Is Here" />
        </StackPanel>
    </DockPanel>
</Window>
Run Code Online (Sandbox Code Playgroud)
using System.Windows;
using System.Windows.Input;

namespace InputBindingSample
{
    public partial class Window1
    {
        public static readonly RoutedUICommand MyUndo = new RoutedUICommand("MyUndo", "MyUndo", typeof(Window1),
            new InputGestureCollection(new[] { new KeyGesture(Key.Z, ModifierKeys.Control) }));

        public Window1() { InitializeComponent(); }

        private void MyUndo_Executed(object sender, ExecutedRoutedEventArgs e) { MessageBox.Show("MyUndo!"); }
    }
}
Run Code Online (Sandbox Code Playgroud)

use*_*587 10

还有就是要剿所有绑定没有简单的方法,不设置IsUndoEnabledfalse,因为它只会陷阱和冲洗Ctrl+ Z键绑定.您需要重定向CanUndo,CanRedo,UndoRedo.这是我如何用我的UndoServiceActions单身人士做的.

textBox.CommandBindings.Add(new CommandBinding(ApplicationCommands.Undo,
                                               UndoCommand, CanUndoCommand));
textBox.CommandBindings.Add(new CommandBinding(ApplicationCommands.Redo,
                                               RedoCommand, CanRedoCommand));

private void CanRedoCommand(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = UndoServiceActions.obj.UndoService.CanRedo;
    e.Handled = true;
}

private void CanUndoCommand(object sender, CanExecuteRoutedEventArgs e)
{
    e.CanExecute = UndoServiceActions.obj.UndoService.CanUndo;
    e.Handled = true;
}

private void RedoCommand(object sender, ExecutedRoutedEventArgs e)
{
    UndoServiceActions.obj.UndoService.Redo();
    e.Handled = true;
}

private void UndoCommand(object sender, ExecutedRoutedEventArgs e)
{
    UndoServiceActions.obj.UndoService.Undo();
    e.Handled = true;
}
Run Code Online (Sandbox Code Playgroud)

  • 真的似乎是唯一的方法......我发现这个蝙蝠屎疯了,好像想要拥有一个跨越许多输入控件的撤销堆栈会很奇怪...... (2认同)

MRo*_*Roc 5

如果要实现自己的撤消/重做并阻止TextBox拦截,请通过CommandManager.AddPreviewCanExecuteHandler和附加到命令预览事件,CommandManager.AddPreviewExecutedHandler并将event.Handled标志设置为true:

MySomething()
{
    CommandManager.AddPreviewCanExecuteHandler(
        this,
        new CanExecuteRoutedEventHandler(OnPreviewCanExecuteHandler));
    CommandManager.AddPreviewExecutedHandler(
        this,
        new ExecutedRoutedEventHandler(OnPreviewExecutedEvent));
}
void OnPreviewCanExecuteHandler(object sender, CanExecuteRoutedEventArgs e)
{
    if (e.Command == ApplicationCommands.Undo)
    {
        e.CanExecute = true;
        e.Handled = true;
    }
    else if (e.Command == ApplicationCommands.Redo)
    {
        e.CanExecute = true;
        e.Handled = true;
    }
}
void OnPreviewExecutedEvent(object sender, ExecutedRoutedEventArgs e)
{
    if (e.Command == ApplicationCommands.Undo)
    {
        // DO YOUR UNDO HERE
        e.Handled = true;
    }
    else if (e.Command == ApplicationCommands.Redo)
    {
        // DO YOUR REDO HERE
        e.Handled = true;
    }
}
Run Code Online (Sandbox Code Playgroud)