2009-12-14 62 views
14

在我的WPF應用程序中,我希望將輸入手勢附加到命令中,以便輸入手勢在主窗口中全局可用,而不管哪個控件具有焦點。WPF:如何防止控件竊取關鍵手勢?

在我的情況下,我想將Key.PageDown綁定到一個命令,但是,只要某些控件接收到焦點(例如TextBox或TreeView控件),這些控件就會接收到這些鍵事件,並且不再觸發該命令。這些控件沒有具體的定義CommandBindingsInputBindings

這是我如何定義我的輸入手勢:

XAML:

<Window x:Class="Window1" 
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" 
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" 
    Title="Window1" Height="300" Width="300" > 
    <StackPanel> 
     <TreeView> 
      <TreeViewItem Header="1"> 
       <TreeViewItem Header="1.1"></TreeViewItem> 
       <TreeViewItem Header="1.2"></TreeViewItem> 
      </TreeViewItem> 
      <TreeViewItem Header="2" ></TreeViewItem> 
     </TreeView> 
     <TextBox /> 
     <Label Name="label1" /> 
    </StackPanel> 
</Window> 

代碼:

using System; 
using System.Windows; 
using System.Windows.Input; 

public static class Commands 
{ 
    private static RoutedUICommand _myCommand; 

    static Commands() 
    { 
     _myCommand = new RoutedUICommand("My Command", 
      "My Command", 
      typeof(Commands), 
      new InputGestureCollection() 
       { 
        new KeyGesture(Key.PageDown, ModifierKeys.None) 
       }); 
    } 

    public static ICommand MyCommand 
    { 
     get { return _myCommand; } 
    } 
} 

public partial class Window1 : Window 
{ 
    public Window1() 
    { 
     InitializeComponent(); 

     CommandBinding cb = new CommandBinding(); 
     cb.Command = Commands.MyCommand; 
     cb.Executed += new ExecutedRoutedEventHandler(cb_Executed); 
     cb.CanExecute += new CanExecuteRoutedEventHandler(cb_CanExecute); 
     this.CommandBindings.Add(cb); 
    } 

    void cb_CanExecute(object sender, CanExecuteRoutedEventArgs e) 
    { 
     e.CanExecute = true; 
    } 

    void cb_Executed(object sender, ExecutedRoutedEventArgs e) 
    { 
     this.label1.Content = string.Format("My Command was executed {0}", DateTime.Now); 
    } 
} 

我已經嘗試捕捉窗口的PreviewKeyDown事件並將其標記爲處理這不得不不是預期的效果。我還將Focusable財產設置爲false。這對TextBox控件有幫助,但對TreeView沒有幫助(並且具有不希望的效果,即TextBox不再可以被編輯,因此它不是我的解決方案)。

所以我的問題是我怎樣才能定義一個鍵盤快捷方式在主窗口無處不在?

回答

10

以下解決方法似乎具有將全局命令用於窗口的預期效果;不過,我仍然不知道是否有WPF做到這一點沒有更簡單的方法:

private void Window_PreviewKeyDown(object sender, KeyEventArgs e) 
{ 
    foreach (InputBinding inputBinding in this.InputBindings) 
    { 
     KeyGesture keyGesture = inputBinding.Gesture as KeyGesture; 
     if (keyGesture != null && keyGesture.Key == e.Key && keyGesture.Modifiers == Keyboard.Modifiers) 
     { 
      if (inputBinding.Command != null) 
      { 
       inputBinding.Command.Execute(0); 
       e.Handled = true; 
      } 
     } 
    } 

    foreach (CommandBinding cb in this.CommandBindings) 
    { 
     RoutedCommand command = cb.Command as RoutedCommand; 
     if (command != null) 
     { 
      foreach (InputGesture inputGesture in command.InputGestures) 
      { 
       KeyGesture keyGesture = inputGesture as KeyGesture; 
       if (keyGesture != null && keyGesture.Key == e.Key && keyGesture.Modifiers == Keyboard.Modifiers) 
       { 
        command.Execute(0, this); 
        e.Handled = true; 
       } 
      } 
     } 
    } 
} 

}

+0

您可能還想檢查InputBindings集合而不是CommandBindings。有時候你在CommandBindings中不會有RoutedCommand ... – Anvaka 2009-12-14 12:42:00

+0

是的,我忘記了,謝謝你的提示:-) – 2009-12-14 12:49:43

+0

這是一個救星。謝謝! – tltjr 2013-09-24 21:41:03

4

使用PreviewKeyDown正是你應該做......的「PreviewXYZ」事件是從下往上(使窗口得到它,然後再控制)......,讓你做什麼解僱任何你想在「窗口」級別上做全局性的。

然後,您可以選擇說「IsHandled = true」,這將阻止它進入下一個控件(就您而言),但您不必這樣做。如果您希望事件冒泡,那麼只需添加您的代碼並將「IsHandled」設置爲false即可。

+0

這就是我試過的。但是,關鍵手勢也會被過濾,而不會傳遞給窗口。 – 2009-12-14 12:01:00

+0

P.S .:這是否意味着我不能在我的命令中使用'InputGestures',而是必須手動切換/處理'PreviewKeyDown'中的關鍵事件?我希望能夠避免在WPF中... – 2009-12-14 12:06:14

+0

說實話,我對InputGestures本身並不是很好(使用它們可能只有一次,而我沒那麼強大)。我的意思是,你可以用PreviewKeyDown來做到這一點。我知道你可以絕對想出你自己的命令並使用手勢......我已經完成了它,但只能在演示和很久以前。 - 也許有人比我更聰明會很快發表評論:) – 2009-12-14 16:52:00

2

不幸的是在WPF一些控件有一些鍵盤處理內部硬編碼。該PreviewKeyDown處理器在主窗口中的答案是

我如何定義鍵盤快捷鍵,在主窗口

問題的作品隨處可見。是的,這意味着你可能想手動在PreviewKeyDown中的關鍵事件上選擇開關/外殼...