Formulare, die nicht auf KeyDown-Ereignisse reagieren

82

Ich habe eine Weile an meinem Windows Forms-Projekt gearbeitet und mich entschlossen, mit Tastaturkürzeln zu experimentieren. Nach einigem Lesen dachte ich, ich müsste nur einen Ereignishandler schreiben und ihn an das KeyDown-Ereignis des Formulars binden:

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.Control && e.Alt && e.KeyCode == Keys.O)
    {
        MessageBox.Show("Ctrl+Alt+O: magic!");
    }
}

Ich habe dies auf die gute alte Weise getan, um das Eigenschaftenfenster des Visual Studio-Designers zu öffnen und dann auf das KeyDown-Ereignis meines Formulars zu doppelklicken, um den Form1_KeyDownEreignishandler zu generieren . Beim Testen meiner Anwendung reagiert das Formular jedoch überhaupt nicht auf die Tastenkombination Ctrl+ Alt+ O. Der Visual Studio-Designer hat den Code generiert, um den Ereignishandler an das Formular zu binden:

private void InitializeComponent()
{
    // ...

    this.KeyDown += new System.Windows.Forms.KeyEventHandler(this.Form1_KeyDown);

    // ...
}

Also habe ich versucht Console.WriteLine(), dem Handler einen Anruf hinzuzufügen , um zu überprüfen, ob er überhaupt aufgerufen wurde, aber auch kein Glück.

Außerdem habe ich versucht, einen Haltepunkt für den Ereignisbindungsaufruf (siehe oben) festzulegen, und festgestellt, dass das Programm diesen Haltepunkt einwandfrei erreicht. Haltepunkte, die ich in der Methodendefinition selbst festgelegt habe, werden jedoch nie erreicht.

Um sicherzustellen, dass ich die ersten Schritte korrekt ausgeführt habe, habe ich versucht, sie zu wiederholen mit:

  • Eine neue Form in der gleichen Lösung.
    Gleiches Problem: Das Formular reagiert nicht, wenn ich die Tastenkombination Ctrl+ Alt+ drücke Ound der Debugger nicht einmal in den Ereignishandler tritt. Versuchte dies erneut und es funktioniert.

  • Eine brandneue WinForms-Lösung.
    Es funktioniert perfekt: Der Nachrichtendialog wird angezeigt (der Console.WriteLine()Anruf funktioniert auch).

Also bin ich hier ziemlich verloren. Was hindert alle Formulare in diesem einen Projekt daran, KeyDown-Ereignisse zu empfangen?

BoltClock
quelle

Antworten:

173

Ist in Ihrem Formular die KeyPreview-Eigenschaft auf true festgelegt?

Form.KeyPreview-Eigenschaft

Ruft einen Wert ab oder legt einen Wert fest, der angibt, ob das Formular Schlüsselereignisse empfängt, bevor das Ereignis an das Steuerelement mit Fokus übergeben wird.

http://msdn.microsoft.com/en-us/library/system.windows.forms.form.keypreview.aspx

STO
quelle
19
Es ist ein Hack, der zur Verfügung gestellt wird, um VB6-Programmierer bei Laune zu halten. Es gibt Probleme mit der Ausführungsreihenfolge. Überschreiben Sie stattdessen ProcessCmdKey ().
Hans Passant
@HansPassant, ich kann nichts finden, was die Probleme bei der Ausführungsreihenfolge erklärt. KeyDown + KeyPreview sieht nicht alle Schlüssel, was ein Problem genug ist, aber was sind die Probleme mit der Ausführungsreihenfolge?
Kdbanman
1
Es gibt viele Überschreibungen, um Tastenkombinationen zu erkennen. KeyPreview + KeyDown wird der Reihe nach ausgeführt und ist zuletzt tot.
Hans Passant
54

Der häufigste Ratschlag für dieses Problem bei StackOverflow und MSDN 1 , 2 (einschließlich der hier akzeptierten Antwort) ist schnell und einfach:

KeyDownEreignisse werden ausgelöst, Formsolange ihre KeyPreviewEigenschaft auf gesetzt isttrue

Das ist für die meisten Zwecke ausreichend, aber aus zwei Gründen riskant:

  1. KeyDownHandler sehen nicht alle Schlüssel . Insbesondere "Sie können die Art der Tastenanschläge, die für die Navigation verwendet werden, nicht sehen. Wie die Cursortasten und die Tabulatortaste, Escape und Enter für einen Dialog."

  2. Es gibt verschiedene Möglichkeiten, Schlüsselereignisse abzufangen, und alle treten nacheinander auf. KeyDownwird zuletzt behandelt . Daher KeyPreviewist es keine große Vorschau, und das Ereignis könnte an einigen Haltestellen auf dem Weg zum Schweigen gebracht werden.

(Gutschrift an @HansPassant für diese Punkte.)

Überschreiben ProcessCmdKeySie stattdessen Folgendes Form:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
    if (keyData == Keys.Up)
    {
        // Handle key at form level.
        // Do not send event to focused control by returning true.
        return true;
    }
  return base.ProcessCmdKey(ref msg, keyData);
}

Auf diese Weise sind alle Schlüssel für die Methode sichtbar, und die Methode steht an erster Stelle, um das Ereignis anzuzeigen.

Beachten Sie, dass Sie weiterhin die Kontrolle darüber haben, ob fokussierte Steuerelemente das KeyDownEreignis sehen oder nicht . Kehren Sie einfach zurück true, um das nachfolgende KeyDownEreignis zu blockieren , anstatt KeyPressEventArgs.Handledes truewie in einem KeyDownEreignishandler festzulegen. Hier ist ein Artikel mit mehr Details.

kdbanman
quelle
1
Dies ist die richtige Antwort, insbesondere wenn Sie feststellen, dass PreviewKeyDown überhaupt nicht ausgelöst wird, wenn KeyPreview auf true gesetzt ist.
Tim
23

Versuchen Sie, die KeyPreviewEigenschaft in Ihrem Formular auf true zu setzen. Dies funktionierte bei mir für die Registrierung von Tastendrücken.

Seb Charrot
quelle