2009-12-14 11 views
14

Nella mia applicazione WPF, vorrei allegare un gesto di input a un comando in modo che il gesto di input sia globalmente disponibile nella finestra principale, indipendentemente dal controllo su cui si trova il focus.WPF: Come impedire a un controllo di rubare un gesto chiave?

Nel mio caso, desidero associare Key.PageDown a un comando, tuttavia, non appena determinati controlli ricevono lo stato attivo (ad esempio un controllo TextBox o TreeView), questi controlli ricevono gli eventi chiave e il comando non viene più attivato. Questi controlli non hanno uno specifico CommandBindings o InputBindings definito.

Questo è come mi definisco il mio gesto di ingresso:

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> 

Codice:

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

Ho già provato la cattura evento della finestra PreviewKeyDown e la marcatura come gestito questo ha avuto non l'effetto desiderato. Ho anche impostato la proprietà Focusable su false. Ciò ha aiutato per i controlli TextBox, ma non per TreeView (e ha l'effetto indesiderato, che il TextBox non può più essere modificato, quindi non è una soluzione per me).

Quindi la mia domanda è: come posso definire una scorciatoia da tastiera che funzioni ovunque nella finestra principale?

risposta

10

La seguente soluzione sembra avere l'effetto desiderato di avere il comando globale alla finestra; tuttavia, mi chiedo ancora se non v'è alcun modo semplice per fare questo 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; 
       } 
      } 
     } 
    } 
} 

}

+0

Puoi anche controllare la raccolta di InputBindings invece di CommandBindings. A volte non hai RoutedCommand in CommandBindings ... – Anvaka

+0

Sì, l'ho dimenticato, grazie per il suggerimento :-) –

+0

Questo è un vero toccasana. Grazie! – tltjr

4

Utilizzando PreviewKeyDown è esattamente ciò che si dovrebbe fare ... gli eventi "PreviewXYZ" licenziato dal basso verso l'alto (quindi la finestra ottiene un primo momento, poi il controllo) ... che ti permette di fare tutto ciò che volevi fare globaly a livello di "Finestra".

Quindi, è possibile scegliere di pronunciare "IsHandled = true" che impedirebbe di passare al controllo successivo (per quanto si è interessati), ma non è necessario. Se vuoi che bolla l'evento, aggiungi il tuo codice e lascia "IsHandled" a false.

+0

Questo è quello che ho provato. Ma poi il gesto chiave viene anche filtrato e non passato alla finestra. –

+0

P.S .: Significa che non posso usare 'InputGestures' sui miei comandi, ma piuttosto dover cambiare/caso sugli eventi chiave in' PreviewKeyDown' manualmente? Speravo che fosse possibile evitarlo in WPF ... –

+0

A dire il vero, non sono molto bravo con InputGestures (li ho usati forse una volta e non sono così forte). Il mio punto era solo che puoi farlo con PreviewKeyDown.So che puoi assolutamente inventare i tuoi comandi e usare i gesti ... l'ho fatto, ma solo in una demo e molto tempo fa. - Forse qualcuno più intelligente di me commenterà presto :) –

2

Purtroppo in WPF alcuni controlli hanno una qualche trasformazione della tastiera hardcoded internamente. Il gestore PreviewKeyDown nella finestra principale è la risposta a

Come posso definire un tasto di scelta rapida che funziona ovunque nella finestra principale

domanda. E sì, vuol dire che potresti voler scegliere switch/case sugli eventi chiave in PreviewKeyDown manualmente ...

Problemi correlati