Der beste Weg, um Tastaturkürzel in einer Windows Forms-Anwendung zu implementieren?

280

Ich suche nach einer besten Möglichkeit, gängige Windows-Tastaturkürzel (z. B. Ctrl+ F, Ctrl+ N) in meiner Windows Forms- Anwendung in C # zu implementieren .

Die Anwendung verfügt über ein Hauptformular, in dem viele untergeordnete Formulare (nacheinander) gehostet werden. Wenn ein Benutzer Ctrl+ Fdrückt, möchte ich ein benutzerdefiniertes Suchformular anzeigen. Das Suchformular hängt vom aktuell geöffneten untergeordneten Formular in der Anwendung ab.

Ich habe darüber nachgedacht, so etwas im ChildForm_KeyDown- Ereignis zu verwenden:

   if (e.KeyCode == Keys.F && Control.ModifierKeys == Keys.Control)
        // Show search form

Das funktioniert aber nicht. Das Ereignis wird nicht einmal ausgelöst, wenn Sie eine Taste drücken. Was ist die Lösung?

Rockcoder
quelle
Es ist wirklich seltsam, dass Winforms keine spezifischen Funktionen dafür zu haben scheint, wie es die native Windows-API tut.
Stewart

Antworten:

460

Sie haben wahrscheinlich vergessen, die KeyPreview- Eigenschaft des Formulars auf True zu setzen. Das Überschreiben der ProcessCmdKey () -Methode ist die generische Lösung:

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
  if (keyData == (Keys.Control | Keys.F)) {
    MessageBox.Show("What the Ctrl+F?");
    return true;
  }
  return base.ProcessCmdKey(ref msg, keyData);
}
Hans Passant
quelle
Dies funktioniert gut, erkennt es aber nur für mich, wenn das Formular das aktive Fenster ist. Weiß jemand, wie man es bindet, damit es in jeder Fensteransicht möglich ist?
Gaʀʀʏ
In manchen Situationen KeyPreviewist dies unverzichtbar. Wenn Sie beispielsweise eine Verknüpfung drücken, müssen Sie die Eingabe unterdrücken, aber dennoch ein separates MenuStripEreignis auslösen. ProcessCmdKeyAnsatz würde die Verdoppelung der Ereignisauslöselogik erzwingen.
Saul
1
Hmm, nein, der KeyDown-Ereignishandler des Formulars unterscheidet sich deutlich vom Click-Ereignishandler eines Menüelements. Sie gehen immer noch genauso vor, indem Sie entweder die Ereignishandlermethode direkt aufrufen (es ist nicht erforderlich, dass sie ausschließlich von einem Ereignis aufgerufen wird) oder die gemeinsame Logik in eine separate Methode umgestalten.
Hans Passant
14
"Was ist die Strg + F?" LOL
kchad
73

Auf Ihrem Hauptformular

  1. Auf KeyPreviewTrue setzen
  2. Fügen Sie den KeyDown-Ereignishandler mit dem folgenden Code hinzu

    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.N)
        {
            SearchForm searchForm = new SearchForm();
            searchForm.Show();
        }
    }
    
Almir
quelle
4
+ für, KeyPreview auf True setzen .. fehlte das
Usman Younas
20

Der beste Weg ist, Menü-Mnemonik zu verwenden, dh Menüeinträge in Ihrem Hauptformular zu haben, denen die gewünschte Tastenkombination zugewiesen wird. Dann wird alles andere intern erledigt und Sie müssen lediglich die entsprechende Aktion implementieren, die im ClickEreignishandler dieses Menüeintrags ausgeführt wird.

Konrad Rudolph
quelle
1
Das Problem ist, dass das Hauptformular keine allgemeinen Windows-Menüs verwendet. Es verwendet ein benutzerdefiniertes Navigationsfeld, in dem untergeordnete Formulare angezeigt werden. Die Suchformulare werden durch Klicken auf den ToolStripButton im untergeordneten Formular aufgerufen.
Rockcoder
menu mnemonicsechte Probe?
Kiquenet
1
@Kiquenet docs.microsoft.com/en-us/dotnet/api/…
Konrad Rudolph
1
Mnemonics sind ein anderes Konzept als Tastenkombinationen, und es gibt wichtige Unterschiede in ihrer Funktionsweise. Kurz gesagt, Mnemonik sind die unterstrichenen Zeichen, die für den Zugriff auf Menüs, Menübefehle und Dialogsteuerelemente über die Tastatur verwendet werden. OTOH, Tastenkombinationen sind eine Möglichkeit, auf Befehle zuzugreifen, ohne die Menüs zu durchlaufen. Außerdem können sie beliebige Tastenanschläge wie Strg + F oder F5 sein, die nicht auf Zeichentasten beschränkt sind.
Stewart
1
@ Stewart Das ist richtig! Meine Antwort wollte nicht implizieren, dass alle Tastaturkürzel Mnemonics sind, sondern nur, dass Menü-Mnemonics der einfachste Weg sind, diese Funktionalität zu erhalten. Wie Rockcoders Kommentar klarstellt, scheint diese Lösung hier leider nicht angemessen zu sein. Ich empfehle es nach Möglichkeit immer noch als bevorzugte Lösung. Für eine allgemeine Lösung ist Hans 'akzeptierte Antwort der Weg nach vorne.
Konrad Rudolph
11

Sie können sogar dieses Beispiel ausprobieren:

public class MDIParent : System.Windows.Forms.Form
{
    public bool NextTab()
    {
         // some code
    }

    public bool PreviousTab()
    {
         // some code
    }

    protected override bool ProcessCmdKey(ref Message message, Keys keys)
    {
        switch (keys)
        {
            case Keys.Control | Keys.Tab:
              {
                NextTab();
                return true;
              }
            case Keys.Control | Keys.Shift | Keys.Tab:
              {
                PreviousTab();
                return true;
              }
        }
        return base.ProcessCmdKey(ref message, keys);
    }
}

public class mySecondForm : System.Windows.Forms.Form
{
    // some code...
}
Shilpa
quelle
8

Wenn Sie ein Menü haben, sollte das Ändern der ShortcutKeysEigenschaft von ToolStripMenuItemden Trick machen.

Wenn nicht, können Sie eine erstellen und ihre visibleEigenschaft auf false setzen.

Corin Blaikie
quelle
Nein, ich habe kein Menü. Der ToolStripButton für die Suche befindet sich tatsächlich im BindingNavigator-Steuerelement, sodass das Hinzufügen eines Menüs wahrscheinlich keine Option ist.
Rockcoder
6

Aus dem Hauptformular müssen Sie:

  • Stellen Sie sicher, dass Sie KeyPreview auf true setzen (standardmäßig TRUE).
  • Fügen Sie MainForm_KeyDown (..) hinzu, mit dem Sie hier beliebige Verknüpfungen festlegen können.

Außerdem habe ich dies bei Google gefunden und wollte es an diejenigen weitergeben, die noch nach Antworten suchen. (für global)

Ich denke, Sie müssen user32.dll verwenden

protected override void WndProc(ref Message m)
{
    base.WndProc(ref m);

    if (m.Msg == 0x0312)
    {
        /* Note that the three lines below are not needed if you only want to register one hotkey.
         * The below lines are useful in case you want to register multiple keys, which you can use a switch with the id as argument, or if you want to know which key/modifier was pressed for some particular reason. */

        Keys key = (Keys)(((int)m.LParam >> 16) & 0xFFFF);                  // The key of the hotkey that was pressed.
        KeyModifier modifier = (KeyModifier)((int)m.LParam & 0xFFFF);       // The modifier of the hotkey that was pressed.
        int id = m.WParam.ToInt32();                                        // The id of the hotkey that was pressed.


        MessageBox.Show("Hotkey has been pressed!");
        // do something
    }
}

Lesen Sie weiter http://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/

Juran
quelle
4

Hans 'Antwort könnte für jemanden, der neu in diesem Bereich ist, etwas einfacher sein. Hier ist meine Version.

Sie müssen sich nicht täuschen KeyPreview, lassen Sie es auf eingestellt false. Um den folgenden Code zu verwenden, fügen Sie ihn einfach unter Ihren Code ein form1_loadund führen F5Sie ihn aus, damit er funktioniert:

protected override void OnKeyPress(KeyPressEventArgs ex)
{
    string xo = ex.KeyChar.ToString();

    if (xo == "q") //You pressed "q" key on the keyboard
    {
        Form2 f2 = new Form2();
        f2.Show();
    }
}
Abhishek Jha
quelle
7
Erstens ist das Überschreiben von ProcessCmdKey die empfohlene Methode zur Behandlung eines Tastenanschlags, der für befehlsähnliche Operationen vorgesehen ist, nach denen das OP gefragt hat. Zweitens haben Sie Hans 'Kommentar über das Setzen von KeyPreview auf true falsch verstanden. Er erzählte dem OP nur, warum seine Technik nicht funktionierte. Das Setzen von KeyPreview auf true ist für die Verwendung von ProcessCmdKey nicht erforderlich.
RenniePet
2

In WinForm können wir den Status des Steuerschlüssels immer erhalten, indem wir:

bool IsCtrlPressed = (Control.ModifierKeys & Keys.Control) != 0;
sk
quelle