Форми не відповідають на події 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?

Відповіді:


174

Чи має ваша форма для властивості KeyPreview значення true?

Властивість Form.KeyPreview

Отримує або встановлює значення, яке вказує, чи форма отримає ключові події до того, як подія буде передана елементу керування, який має фокус.

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


19
Це хакер, який доступний для задоволення програмістів VB6. У нього проблеми із порядком виконання, замість цього перевизначте ProcessCmdKey ().
Ганс Пассант,

@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обробник подій. Ось стаття з більш докладною інформацією.


1
Це правильна відповідь, особливо якщо ви виявите, що PreviewKeyDown взагалі не запускатиметься, якщо для KeyPreview встановлено значення true.
Тім

23

Спробуйте встановити KeyPreviewвластивість у формі на true. Це спрацювало для мене при реєстрації натискань на клавіші.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.