2009-09-03 58 views
11

我想獲得撤消/重做鍵盤快捷鍵在我的WPF應用程序(我有我自己的自定義功能實現使用Command Pattern)工作。但是,似乎TextBox控件攔截了我的「撤消」RoutedUICommand。WPF TextBox攔截RoutedUICommands

禁用此功能的最簡單方法是什麼,以便我可以在我的UI樹的根上捕獲Ctrl + Z?如果可能的話,我想避免在我的應用程序中將大量的代碼/ XAML放入每個TextBox

下面簡要說明了該問題:

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

回答

10

還有就是剿所有綁定沒有直接的方式,不設IsUndoEnabledfalse,因爲它只會陷阱和沖洗按Ctrl +ž關鍵結合。您需要重定向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; 
} 
+2

真的似乎是唯一的方法...我發現這個蝙蝠狗屎瘋了,好像它會奇怪想要有一個跨越很多輸入控件的撤消堆棧... – flq 2013-01-14 17:16:16

+0

我得到了這個工作。您必須確保使用應用程序命令而不是自定義命令。您還必須將IsUndoEnabled設置爲false,否則它仍將執行文本框實現的撤消操作。 – Asheh 2014-07-25 06:55:06

0

TextBoxBase(並因此TextBoxRichTextBox)具有IsUndoEnabled屬性,默認爲true。如果將它設置爲false(並且您可以像平常一樣通過樣式和設置器爲窗口上的所有文本框執行此操作),那麼它們將不會攔截Ctrl + Z。

+0

奇怪。向TextBox添加IsUndoEnabled =「False」仍然沒有給出預期的結果(顯示MessageBox)。還有什麼我失蹤? – 2009-09-03 19:47:40

0

控制提供IsUndoEnabled屬性,您可以將 設置爲false以防止撤消功能。 (如果IsUndoEnabledtrue,該按Ctrl +ž按鍵觸發它。)

而且對於不提供,你可以添加一個新的綁定爲要禁用的命令的一個特殊屬性控制。然後該綁定 可以提供總是響應false的新的CanExecute事件處理程序。下面是一個使用這種技術來消除對文本框的剪切功能支持的 例如:

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; 
} 
0

默認目標RoutedUICommand是鍵盤焦點的元素。但是,您可以在發出命令的控件上設置CommandTarget以更改接收該命令的根元素。

<MenuItem Command="ApplicationCommands.Open" 
      CommandTarget="{Binding ElementName=UIRoot}" 
      Header="_Open" /> 
0

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。您可能不需要使用自定義命令(只需使用內置的撤銷)。

5

如果你想實現自己的撤銷/重做,防止文本框截獲,通過CommandManager.AddPreviewCanExecuteHandlerCommandManager.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; 
    } 
} 
+0

當有多個控件(不同類型)在場時,此解決方案似乎更可取。 – karmasponge 2012-09-04 02:52:52