La meilleure façon d'implémenter des raccourcis clavier dans une application Windows Forms?

280

Je recherche un meilleur moyen d'implémenter des raccourcis clavier Windows courants (par exemple Ctrl+ F, Ctrl+ N) dans mon application Windows Forms en C #.

L'application a un formulaire principal qui héberge de nombreux formulaires enfants (un à la fois). Lorsqu'un utilisateur frappe Ctrl+ F, j'aimerais afficher un formulaire de recherche personnalisé. Le formulaire de recherche dépendrait du formulaire enfant ouvert actuel dans l'application.

Je pensais utiliser quelque chose comme ça dans l' événement ChildForm_KeyDown :

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

Mais ça ne marche pas. L'événement ne se déclenche même pas lorsque vous appuyez sur une touche. Quelle est la solution?

Rockcoder
la source
Il est vraiment étrange que Winforms ne semble pas avoir de fonctionnalités spécifiques pour cela comme le fait l'API Windows native.
Stewart

Réponses:

460

Vous avez probablement oublié de définir la propriété KeyPreview du formulaire sur True. La substitution de la méthode ProcessCmdKey () est la solution générique:

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
la source
Cela fonctionne bien, mais ne le détecte pour moi que si le formulaire est la fenêtre active. Quelqu'un sait comment le lier, donc dans n'importe quelle fenêtre, c'est possible?
Gaʀʀʏ
Dans certaines situations, KeyPreviewc'est tout à fait indispensable. Par exemple, lorsque vous appuyez sur un raccourci, vous devez supprimer l'entrée mais néanmoins permettre à un MenuStripévénement distinct de se déclencher. ProcessCmdKeyCette approche forcerait la duplication de la logique de déclenchement des événements.
Saul
1
Hmm, non, le gestionnaire d'événements KeyDown du formulaire est assez distinct du gestionnaire d'événements Click d'un élément de menu. Vous faites toujours exactement la même chose, soit appelez directement la méthode du gestionnaire d'événements (pas besoin qu'elle soit exclusivement appelée par un événement) ou refactorisez la logique commune dans une méthode distincte.
Hans Passant
14
"Qu'est-ce que le Ctrl + F?" LOL
kchad
73

Sur votre formulaire principal

  1. Défini KeyPreviewsur True
  2. Ajouter un gestionnaire d'événements KeyDown avec le code suivant

    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.N)
        {
            SearchForm searchForm = new SearchForm();
            searchForm.Show();
        }
    }
    
Almir
la source
4
+ pour, Définir KeyPreview sur True .. manquait cela
Usman Younas
20

La meilleure façon est d'utiliser des mnémoniques de menu, c'est-à-dire d'avoir des entrées de menu dans votre formulaire principal qui reçoivent le raccourci clavier que vous souhaitez. Ensuite, tout le reste est géré en interne et tout ce que vous avez à faire est d'implémenter l'action appropriée qui est exécutée dans le Clickgestionnaire d'événements de cette entrée de menu.

Konrad Rudolph
la source
1
Le problème est que le formulaire principal n'utilise pas les menus Windows courants. Il utilise un panneau de navigation personnalisé qui est utilisé pour afficher les formulaires enfants. Les formulaires de recherche sont invoqués en cliquant sur le ToolStripButton sur le formulaire enfant.
Rockcoder
menu mnemonicséchantillon réel?
Kiquenet
1
@Kiquenet docs.microsoft.com/en-us/dotnet/api/…
Konrad Rudolph
1
Les mnémoniques sont un concept distinct des touches de raccourci, et il existe des différences importantes dans leur fonctionnement. En bref, les mnémoniques sont les caractères soulignés utilisés pour accéder aux menus, aux commandes de menu et aux commandes de dialogue à l'aide du clavier. OTOH, les touches de raccourci sont un moyen d'accéder aux commandes sans passer par les menus, et en plus elles peuvent être des frappes arbitraires comme Ctrl + F ou F5, non limitées aux touches de caractères.
Stewart
1
@Stewart C'est exact! Ma réponse n'essayait pas d'impliquer que tous les raccourcis clavier sont des mnémoniques, mais simplement que les mnémoniques des menus sont le moyen le plus simple d'obtenir cette fonctionnalité. Malheureusement, comme le commentaire de Rockcoder le clarifie, cette solution ne semble pas appropriée ici. Je le recommande toujours comme solution préférable, dans la mesure du possible. Pour une solution générale, la réponse acceptée par Hans est la voie à suivre.
Konrad Rudolph
11

Vous pouvez même essayer cet exemple:

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
la source
8

Si vous avez un menu, changer la ShortcutKeyspropriété de ToolStripMenuItemdevrait faire l'affaire.

Sinon, vous pouvez en créer un et définir sa visiblepropriété sur false.

Corin Blaikie
la source
Non, je n'ai pas de menu. ToolStripButton pour la recherche se trouve en fait sur le contrôle BindingNavigator, l'ajout d'un menu n'est donc probablement pas une option.
Rockcoder
6

A partir du formulaire principal, vous devez:

  • Assurez-vous de définir KeyPreview sur true (TRUE par défaut)
  • Ajoutez MainForm_KeyDown (..) - par lequel vous pouvez définir ici les raccourcis que vous souhaitez.

De plus, je l'ai trouvé sur Google et je voulais le partager avec ceux qui recherchent toujours des réponses. (pour global)

Je pense que vous devez utiliser user32.dll

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

Pour en savoir plus, consultez http://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/

Juran
la source
4

La réponse de Hans pourrait être un peu plus facile pour quelqu'un de nouveau, alors voici ma version.

Vous n'avez pas besoin de vous tromper KeyPreview, laissez-le réglé sur false. Pour utiliser le code ci-dessous, collez-le juste en dessous de votre form1_loadet exécutez avec F5pour le voir fonctionner:

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
la source
7
Tout d'abord, la substitution de ProcessCmdKey est la méthode recommandée pour gérer une frappe destinée à effectuer une opération de type commande, ce à quoi l'OP demandait. Deuxièmement, vous avez mal compris le commentaire de Hans sur la définition de KeyPreview sur true; il disait juste au PO pourquoi sa technique ne fonctionnait pas. Il n'est pas nécessaire de définir KeyPreview sur true pour utiliser ProcessCmdKey.
RenniePet
2

Dans WinForm, nous pouvons toujours obtenir l'état de la clé de contrôle en:

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