2009-12-14 17 views
14

En mi aplicación WPF me gustaría adjuntar un gesto de entrada a un comando para que el gesto de entrada esté disponible globalmente en la ventana principal, sin importar qué control tenga el foco.WPF: ¿Cómo evitar que un control robe un gesto clave?

En mi caso, me gustaría vincular Key.PageDown a un comando, sin embargo, tan pronto como ciertos controles reciben el foco (por ejemplo, un control TextBox o TreeView), estos controles reciben los eventos clave y el comando ya no se activa. Estos controles no tienen definidos CommandBindings o InputBindings específicos.

Esto es como defino mi gesto de entrada:

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> 

Código:

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

ya he intentado coger el evento de la ventana PreviewKeyDown y marcándolo como manejado Este tenía no es el efecto deseado También configuré la propiedad Focusable en false. Esto ayudó para los controles TextBox, pero no para TreeView (y tiene el efecto no deseado, que el TextBox ya no se puede editar, por lo que no es una solución para mí).

Así que mi pregunta es ¿cómo puedo definir un atajo de teclado que funcione en todas partes en la ventana principal?

Respuesta

10

La siguiente solución parece tener el efecto deseado de tener el comando global en la ventana; Sin embargo, todavía me pregunto si no hay manera más fácil de hacer esto en 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

También es posible que desee comprobar la colección de InputBindings en lugar de CommandBindings. A veces no tendrás RoutedCommand en CommandBindings ... – Anvaka

+0

Sí, me olvidé de eso, gracias por el consejo :-) –

+0

Esto es un salvavidas. ¡Gracias! – tltjr

4

Usando PreviewKeyDown es exactamente lo que debe ... qué los eventos "PreviewXYZ" es despedido de abajo hacia arriba (por lo que la ventana se pone en primer lugar, a continuación, el control) ... que le permite hacer lo que sea querías hacer global en el nivel "Ventana".

Luego, puede elegir decir "IsHandled = true", lo que evitaría que pase al siguiente control (en lo que a usted respecta), pero no tiene que hacer esto. Si desea que el evento burbujee, simplemente agregue su código y deje "IsHandled" en false.

+0

Eso es lo que probé. Pero luego el gesto clave también se filtra y no se pasa a la ventana. –

+0

P.S .: ¿Eso significa que no puedo usar 'InputGestures' en mis comandos sino tener que cambiar/caso en los eventos clave en' PreviewKeyDown' manualmente? Esperaba que fuera posible evitar eso en WPF ... –

+0

Para ser honesto, no soy muy bueno con InputGestures (los usé una vez y no soy tan fuerte). Mi punto era que puedes hacerlo con PreviewKeyDown.Sé que puedes crear tus propios comandos y usar los gestos ... Lo he logrado, pero solo en una demostración y hace mucho tiempo. - Tal vez alguien más inteligente que yo comentará pronto :) –

2

Por desgracia, en algunos controles WPF tienen algún tipo de procesamiento teclado codificado internamente. El manejador PreviewKeyDown en la ventana principal es la respuesta a

¿Cómo puedo definir un atajo de teclado que funciona en todas partes en la ventana principal

cuestión. Y sí, significa que es posible que desee elegir switch/case en los eventos clave en PreviewKeyDown manualmente ...

Cuestiones relacionadas