2009-12-14 24 views
14

In meiner WPF-Anwendung möchte ich eine Eingabegeste an einen Befehl anhängen, so dass die Eingabegeste im Hauptfenster global verfügbar ist, egal welches Steuerelement den Fokus hat.WPF: Wie verhindert man, dass ein Steuerelement eine Tastengeste stiehlt?

In meinem Fall möchte ich Key.PageDown an einen Befehl binden, aber sobald bestimmte Steuerelemente den Fokus erhalten (z. B. ein TextBox- oder TreeView-Steuerelement), erhalten diese Steuerelemente die Schlüsselereignisse und der Befehl wird nicht mehr ausgelöst. Diese Kontrollen haben keine spezifischen CommandBindings oder InputBindings definiert.

Dies ist, wie ich meine Eingabegeste definieren:

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

Ich habe bereits versucht, die PreviewKeyDown Veranstaltung Fenster Fang- und Markierungs es Dies hatte als behandelt nicht der gewünschte Effekt. Ich setze auch die Eigenschaft auf false. Dies half bei TextBox-Steuerelementen, aber nicht bei der TreeView (und hat den unerwünschten Effekt, dass die TextBox nicht mehr bearbeitet werden kann, so dass sie für mich keine Lösung darstellt).

Also meine Frage ist, wie kann ich eine Tastenkombination definieren, die überall im Hauptfenster funktioniert?

Antwort

10

Die folgende Problemumgehung scheint den gewünschten Effekt zu haben, den Befehl global auf das Fenster zu haben; aber ich frage mich immer noch, ob es gibt keinen einfacheren Weg, dies in WPF zu tun:

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

Sie können auch die EingabeBindings-Sammlung anstelle von CommandBindings überprüfen. Manchmal hast du keinen RoutedCommand in CommandBindings ... – Anvaka

+0

Ja, das habe ich vergessen, danke für den Tipp :-) –

+0

Das ist ein Lebensretter. Vielen Dank! – tltjr

4

Mit PreviewKeyDown ist genau das, was Sie sollte tun ... die „PreviewXYZ“ Ereignisse von unten nach oben abgefeuert werden (so das Fenster wird es zuerst, dann die Kontrolle) ... das können Sie tun, was auch immer Sie wollten global auf der Ebene "Window" arbeiten.

Dann können Sie "IsHandled = true" sagen, was verhindern würde, dass es zum nächsten Steuerelement geht (was Sie betrifft), aber Sie müssen dies nicht tun. Wenn das Ereignis platzen soll, fügen Sie einfach Ihren Code hinzu und lassen Sie "IsHandled" auf false.

+0

Das habe ich versucht. Aber dann wird auch die Tastengeste gefiltert und nicht an das Fenster übergeben. –

+0

P.S .: Bedeutet das, dass ich 'InputGestures' nicht für meine Befehle verwenden kann, sondern die Schlüsselereignisse in 'PreviewKeyDown' manuell umschalten muss? Ich hatte gehofft, dass es möglich ist, das in WPF zu vermeiden ... –

+0

Um ehrlich zu sein, bin ich nicht sehr gut mit InputGestures selbst (benutzte sie vielleicht einmal und ich bin nicht so stark). Mein Punkt war nur, dass Sie es mit PreviewKeyDown machen können.Ich weiß, dass Sie absolut Ihre eigenen Befehle entwickeln und die Gesten verwenden können ... Ich habe es getan, aber nur in einer Demo und vor langer Zeit. - Vielleicht wird jemand, der schlauer ist als ich, bald kommentieren. –

2

Leider gibt es in WPF einige Steuerelemente haben einige Tastatur-Verarbeitung intern fest einprogrammiert. Die PreviewKeyDown Handler im Hauptfenster ist die Antwort auf

Wie kann ich eine Tastenkombination definieren, die überall im Hauptfenster funktioniert

Frage. Und ja, es bedeutet, dass Sie möglicherweise Schalter/Fall für die Schlüsselereignisse in PreviewKeyDown manuell auswählen möchten ...

Verwandte Themen