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しないでください。、、およびをリダイレクトする必要があります。シングルトンでそれを行う方法は次のとおりです。falseCtrlZCanUndoCanRedoUndoRedoUndoServiceActions

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

独自のUndo/Redoを実装し、TextBoxがインターセプトしないようにする場合は、コマンドプレビューイベントにアタッチしてCommandManager.AddPreviewCanExecuteHandlerCommandManager.AddPreviewExecutedHandlerevent.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

By default the target of the RoutedUICommand is the element with keyboard focus. However, you can set CommandTarget on the control emitting the command in order to change the root element that receives the command.

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

Executed イベントはバブルアップするため、Window Executed イベントは常に TextBox Executed イベントの後に発生します。これを PreviewExecuted に変更してみてください。大きな違いが生じるはずです。また、ウィンドウにも CanExecute を接続する必要がある場合があります。すなわち:

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

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

もちろん、CanExecute をいつ true に設定する必要があるかを判断するロジックが必要になるでしょう。おそらく、カスタム コマンドも使用する必要はありません (組み込みの Undo を使用するだけです)。

于 2009-09-03T20:13:04.493 に答える
0

TextBoxコントロールは、元に戻す機能を防ぐために設定できるプロパティを提供しますIsUndoEnabledfalse(の場合、+キーストロークIsUndoEnabledがトリガーされます。)trueCtrlZ

また、特別なプロパティを提供しないコントロールの場合は、無効にするコマンドの新しいバインディングを追加できます。このバインディングは、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 に答える
0

TextBoxBase(したがってTextBoxRichTextBox) にはIsUndoEnabledプロパティがあり、デフォルトはtrueです。に設定した場合false(そして、通常どおり、スタイルとセッターを介してウィンドウ上のすべてのテキスト ボックスに対してイベントを実行できます)、それらは Ctrl+Z をインターセプトしません。

于 2009-09-03T19:43:32.520 に答える