Лучший способ реализовать сочетания клавиш в приложении Windows Forms?


280

Я ищу лучший способ реализовать общие сочетания клавиш Windows (например, Ctrl+ F, Ctrl+ N) в моем приложении Windows Forms в C #.

Приложение имеет основную форму, которая содержит много дочерних форм (по одной). Когда пользователь нажимает Ctrl+ F, я хотел бы показать пользовательскую форму поиска. Форма поиска будет зависеть от текущей открытой дочерней формы в приложении.

Я думал об использовании чего-то подобного в событии ChildForm_KeyDown :

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

Но это не работает. Событие даже не срабатывает при нажатии клавиши. Каково решение?


Действительно странно, что Winforms, кажется, не имеют специфической функциональности для этого, как в собственном Windows API.
— Стюарт

Ответы:


460

Возможно, вы забыли установить для свойства KeyPreview формы значение True. Переопределение метода ProcessCmdKey () является общим решением:

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

Это работает хорошо, но обнаруживает это только для меня, если форма является активным окном. Кто-нибудь знает, как его связать, чтобы в любом окне было возможно?
— Gaʀʀʏ

В некоторых ситуациях KeyPreviewэто совершенно необходимо. Например, при нажатии на ярлык требуется подавить ввод, но, тем не менее, разрешить запуск отдельного MenuStripсобытия. ProcessCmdKeyподход заставил бы дублировать логику запуска событий.
— Сол

1
Хм, нет, обработчик события KeyDown формы совершенно отличается от обработчика события Click элемента меню. Вы по-прежнему делаете то же самое, либо вызываете метод обработчика событий напрямую (нет необходимости вызывать его исключительно событием), либо реорганизуете общую логику в отдельный метод.
— Ганс Пассант

14
"Что такое Ctrl + F?" LOL
— кчад

73

На вашей основной форме

  1. Установите KeyPreviewв True
  2. Добавьте обработчик события KeyDown с помощью следующего кода

    private void MainForm_KeyDown(object sender, KeyEventArgs e)
    {
        if (e.Control && e.KeyCode == Keys.N)
        {
            SearchForm searchForm = new SearchForm();
            searchForm.Show();
        }
    }
    

4
+ для, установите KeyPreview в True .. не хватало этого
— Усман Юнас

20

Лучший способ - использовать мнемонику меню, то есть иметь пункты меню в основной форме, которым назначены нужные сочетания клавиш. Затем все остальное обрабатывается внутренне, и все, что вам нужно сделать, это реализовать соответствующее действие, которое выполняется в Clickобработчике события этого пункта меню.


1
Проблема в том, что основная форма не использует общие меню окон. Он использует пользовательскую панель навигации, которая используется для отображения дочерних форм. Формы поиска вызываются нажатием на ToolStripButton дочерней формы.
— Rockcoder

menu mnemonicsреальный образец?
— Kiquenet


1
Мнемоника отличается от сочетаний клавиш, и существуют важные различия в том, как они работают. Вкратце, мнемоника - это подчеркнутые символы, используемые для доступа к меню, командам меню и элементам управления диалогов с помощью клавиатуры. OTOH, сочетания клавиш - это способ доступа к командам без прохождения через меню, и, кроме того, они могут быть произвольными нажатиями клавиш, такими как Ctrl + F или F5, не ограничиваясь символьными клавишами.
— Стюарт

1
@ Стюарт Это правильно! В моем ответе я не пытался предположить, что все сочетания клавиш являются мнемоникой, а просто то, что меню - это самый простой способ получить эту функциональность. К сожалению, как поясняет комментарий Rockcoder, это решение здесь не кажется подходящим. Я все еще рекомендую это как предпочтительное решение, где это возможно. Для общего решения принятый ответ Ганса - путь вперед.
— Конрад Рудольф

11

Вы даже можете попробовать этот пример:

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

8

Если у вас есть меню, то изменение ShortcutKeysсвойства ToolStripMenuItemдолжно помочь.

Если нет, вы можете создать его и установить для его visibleсвойства значение false.


Нет, у меня нет меню. ToolStripButton для поиска фактически находится в элементе управления BindingNavigator, поэтому добавление меню, вероятно, не вариант.
— Rockcoder

6

Из основной формы вы должны:

  • Убедитесь , что вы установили KeyPreview к истинным (TRUE , по умолчанию)
  • Добавьте MainForm_KeyDown (..) - с помощью которого вы можете установить здесь любые ярлыки, которые вы хотите.

Кроме того, я нашел это в Google, и я хотел бы поделиться этим с теми, кто все еще ищет ответы. (для глобального)

Я думаю, что вы должны использовать 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
    }
}

Далее читайте это http://www.fluxbytes.com/csharp/how-to-register-a-global-hotkey-for-your-application-in-c/


4

Кто-то новичок в этом вопросе может немного облегчить ответ Ханса , так что вот моя версия.

Вам не нужно дурачиться KeyPreview, оставьте его установленным на false. Чтобы использовать приведенный ниже код, просто вставьте его под свой form1_loadи запустите, F5чтобы увидеть, как он работает:

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

7
Во-первых, переопределение ProcessCmdKey - это рекомендуемый способ обработки нажатия клавиш, предназначенный для выполнения некоторой командоподобной операции, о которой спрашивал OP. Во-вторых, вы неправильно поняли комментарий Ганса о том, что для KeyPreview задано значение true; он просто рассказывал ОП, почему его техника не работает. Установка KeyPreview в true не требуется для использования ProcessCmdKey.
— Ренни Пит

2

В WinForm мы всегда можем получить статус управляющего ключа:

bool IsCtrlPressed = (Control.ModifierKeys & Keys.Control) != 0;
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.