Формы не отвечают на события KeyDown

82

Некоторое время я работал над своим проектом Windows Forms и решил поэкспериментировать с сочетаниями клавиш. После небольшого чтения я решил, что мне нужно просто написать обработчик событий и привязать его к событию KeyDown формы:

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

Я сделал это старым добрым способом, открыв панель свойств дизайнера Visual Studio, а затем дважды щелкнув событие KeyDown в моей форме, чтобы сгенерировать Form1_KeyDownобработчик событий. Но при тестировании моего приложения форма вообще не реагирует на сочетание клавиш Ctrl+ Alt+ O. Однако дизайнер Visual Studio сгенерировал код для привязки обработчика событий к форме:

private void InitializeComponent()
{
    // ...

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

    // ...
}

Поэтому я попытался добавить Console.WriteLine()вызов обработчику, чтобы проверить, что он вообще вызывается, но и в этом не повезло.

Кроме того, я попытался установить точку останова для вызова привязки события (показанный чуть выше) и обнаружил, что программа без проблем достигает этой точки останова. Но любые точки останова, которые я установил в самом определении метода, никогда не достигаются.

Чтобы убедиться, что первые несколько шагов я делаю правильно, я попытался повторить их:

  • Новая форма в том же растворе.
    Та же проблема: форма не отвечает, когда я нажимаю Ctrl комбинацию клавиш + Alt+, Oа отладчик даже не входит в обработчик событий. Попробовал еще раз, и он работает.

  • Совершенно новое решение WinForms.
    Работает отлично: появляется диалог сообщения ( Console.WriteLine()звонок тоже работает).

Так что я совершенно потерялся здесь. Что мешает всем формам в этом одном проекте получать события KeyDown?

BoltClock
источник

Ответы:

174

У вашей формы свойство KeyPreview установлено в значение true?

Свойство Form.KeyPreview

Возвращает или задает значение, указывающее, будет ли форма получать ключевые события до того, как событие будет передано элементу управления, имеющему фокус.

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

СТО
источник
19
Это хитрость, доступная, чтобы порадовать программистов VB6. У него есть проблемы с порядком выполнения, вместо этого переопределите ProcessCmdKey ().
Hans Passant
@HansPassant, я не могу найти ничего, что объясняет проблемы с порядком выполнения. KeyDown + KeyPreview не будет видеть все ключи, что является проблемой, но каковы проблемы с порядком выполнения?
kdbanman
1
Существует множество переопределений для обнаружения нажатий клавиш. Выполняемые по порядку, KeyPreview + KeyDown мертв последним.
Ханс Пассан
54

Самый распространенный совет по решению этой проблемы в StackOverflow и MSDN 1 , 2 (включая принятый здесь ответ) - быстрый и простой:

KeyDownсобытия запускаются, Formпока его KeyPreviewсвойство установлено наtrue

Этого достаточно для большинства целей, но это рискованно по двум причинам:

  1. KeyDownобработчики не видят все ключи . В частности, «вы не можете видеть, какие нажатия клавиш используются для навигации. Например, клавиши курсора и Tab, Escape и Enter для диалогового окна».

  2. Есть несколько различных способов перехвата ключевых событий, и все они происходят последовательно. KeyDownобрабатывается в последнюю очередь . Следовательно, KeyPreviewэто не так уж и много для предварительного просмотра, и событие можно было бы отключить на нескольких остановках по пути.

(Благодарим @HansPassant за эти баллы.)

Вместо этого переопределите ProcessCmdKeyв своем 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);
}

Таким образом, все ключи будут видны методу, и метод будет первым в очереди, чтобы увидеть событие.

Обратите внимание, что вы по-прежнему можете контролировать, видят ли KeyDownсобытие сфокусированные элементы управления . Просто вернуться , trueчтобы блокировать последующее KeyDownсобытие, а не устанавливать , KeyPressEventArgs.Handledчтобы , trueкак вы бы в KeyDownобработчик событий. Вот статья с более подробной информацией.

kdbanman
источник
1
Это правильный ответ, особенно если вы обнаружите, что PreviewKeyDown вообще не срабатывает, если для KeyPreview установлено значение true.
Тим
23

Попробуйте установить для KeyPreviewсвойства в вашей форме значение true. Это сработало для меня для регистрации нажатий клавиш.

Себ Шарро
источник