问题
In my WPF application I would like to attach an input gesture to a command so that the input gesture is globally available in the main window, no matter which control has the focus.
In my case I would like to bind Key.PageDown
to a command, however, as soon as certain controls receive the focus (e.g. a TextBox or TreeView control), these controls receive the key events and the command is no longer triggered. These controls have no specific CommandBindings
or InputBindings
defined.
This is how I define my input gesture:
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>
Code:
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);
}
}
I already tried catching the window's PreviewKeyDown
event and marking it as handled This had not the desired effect. I also set the Focusable
property to false
. This helped for TextBox controls, but not for the TreeView (and has the unwanted effect, that the TextBox no longer can be edited so it is not a solution for me).
So my question is how can I define a keyboard shortcut that works everywhere in the main window?
回答1:
The following workaround seems to have the desired effect of having the command global to the window; however, I still wonder whether there is no easier way to do this in 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;
}
}
}
}
}
}
回答2:
Using PreviewKeyDown is exactly what you should do... the "PreviewXYZ" events are fired from the bottom up (so the Window gets it first, then the control)... that lets you do whatever you wanted to do globaly on the "Window" level.
Then, you can choose to say "IsHandled = true" which would prevent it from going to the next control (as far as you are concerned), but you don't have to do this. If you want the event to bubble, then just add your code and leave "IsHandled" to false.
回答3:
Unfortunately in WPF some controls have some keyboard processing hardcoded internally. The PreviewKeyDown
handler in the main window is the answer to
How can I define a keyboard shortcut that works everywhere in the main window
question. And yes, it does mean that you may want to choose switch/case on the key events in the PreviewKeyDown manually...
来源:https://stackoverflow.com/questions/1900450/wpf-how-to-prevent-a-control-from-stealing-a-key-gesture