11

我正在尝试在我的 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>

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!"); }
    }
}
4

6 回答 6

11

没有直接的方法来抑制所有绑定,不要设置IsUndoEnabled为,false因为它只会捕获和刷新Ctrl+Z键绑定。您需要重定向CanUndoCanRedo和。这是我如何处理我的单身人士。UndoRedoUndoServiceActions

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;
}
于 2010-05-23T05:42:41.487 回答
5

如果要实现自己的撤消/重做并防止 TextBox 拦截,请通过CommandManager.AddPreviewCanExecuteHandlerand附加到命令预览事件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;
    }
}
于 2010-06-28T22:06:17.920 回答
1

默认情况下,目标RoutedUICommand是具有键盘焦点的元素。但是,您可以CommandTarget在发出命令的控件上进行设置,以更改接收命令的根元素。

<MenuItem Command="ApplicationCommands.Open"
          CommandTarget="{Binding ElementName=UIRoot}"
          Header="_Open" />
于 2009-09-03T19:53:59.360 回答
1

Executed 事件会冒泡,因此 Window Executed 事件将始终在 TextBox Executed 事件之后触发。尝试将其更改为 PreviewExecuted,它应该会产生巨大的影响。此外,您可能还需要为您的窗口连接一个 CanExecute。IE:

<CommandBinding Command="Undo" PreviewExecuted="MyUndo_Executed" CanExecute="SomeOtherFunction"/>

private void SomeOtherFunction(object sender, ExecutedRoutedEventArgs e) { e.CanExecute=true; }

当然,您可能需要一些逻辑来确定何时应将 CanExecute 设置为 true。您可能也不需要使用自定义命令(只需使用内置的撤消)。

于 2009-09-03T20:13:04.493 回答
0

TextBoxBase(因此TextBoxand RichTextBox)具有IsUndoEnabled属性,默认为true. 如果您将其设置为false(并且您可以像往常一样通过样式和设置器为窗口上的所有文本框执行此操作),那么它们将不会拦截 Ctrl+Z。

于 2009-09-03T19:43:32.520 回答
0

TextBox控件提供了一个IsUndoEnabled属性,您可以设置该属性false以阻止撤消功能。(如果IsUndoEnabledtrueCtrl+Z按键触发它。)

此外,对于不提供特殊属性的控件,您可以为要禁用的命令添加新绑定。然后,此绑定可以提供一个CanExecute始终响应为 false 的新事件处理程序。下面是一个使用此技术删除对文本框剪切功能的支持的示例:

CommandBinding commandBinding = new CommandBinding(
ApplicationCommands.Cut, null, SuppressCommand);
txt.CommandBindings.Add(commandBinding);

CanExecute这是设置状态的事件处理程序:

private void SuppressCommand(object sender, CanExecuteRoutedEventArgs e)
{
  e.CanExecute = false;
  e.Handled = true;
}
于 2009-09-03T19:44:48.010 回答