Подтвердить что ты не робот

Недостаток настройки Form.KeyPreview = true?

Интересно, какое свойство Form.KeyPreview действительно полезно? Почему это существует и что я "рискую", установив его в true? Я предполагаю, что он должен иметь какой-то негативный эффект - иначе он вообще не должен существовать (или, по крайней мере, быть истинным по умолчанию)?

EDIT. Я прекрасно знаю, что он делает. Я спрашиваю почему. Почему я должен установить его в true, чтобы активировать события клавиатуры? Почему события клавиатуры не срабатывают для формы. Что не только стандартное поведение?

Конкретная причина, по которой я спрашиваю: я только что установил KeyPreview = true в базовой форме моего приложения, которое наследует все остальные формы. Могу ли я за любой неприятный сюрприз?

4b9b3361

Ответ 1

Form.KeyPreview - это бит анахронизма, унаследованный от объектной модели Visual Basic для разработки формы. Вернувшись в дни VB6, вам понадобилось KeyPreview, чтобы реализовать короткие нажатия клавиш. Это больше не требуется в Windows Forms, лучшим решением является ProcessCmdKey():

protected override bool ProcessCmdKey(ref Message msg, Keys keyData) {
  if (keyData == (Keys.Control | Keys.F)) {
    DoSomething();   // Implement the Ctrl+F short-cut keystroke
    return true;     // This keystroke was handled, don't pass to the control with the focus
  }
  return base.ProcessCmdKey(ref msg, keyData);
}

Но поддержка KeyPreview помогла легиону программистов VB6 переключиться на .NET еще в начале 2000-х. Точка KeyPreview или ProcessCmdKey() должна позволить вашему пользовательскому интерфейсу реагировать на нажатия клавиш. Сообщения клавиатуры обычно отправляются в элемент управления, который имеет фокус. Цикл сообщений Windows Forms позволяет коду заглядывать в это сообщение до того, как элемент управления увидит его. Это важно для коротких клавиш, реализация события KeyDown для каждого элемента управления, который может получить фокус для их обнаружения, очень непрактична.

Настройка KeyPreview на True не вызывает проблем. Событие формы KeyDown будет запущено, это будет иметь значение только в том случае, если у него есть код, который что-то делает с нажатием клавиши. Но будьте осторожны, что он внимательно следит за использованием VB6, вы не можете видеть, какие нажатия клавиш используются для навигации. Как и клавиши курсора и Tab, Escape и Enter для диалога. Не проблема с ProcessCmdKey().

Ответ 2

От MSDN

Если для этого свойства установлено значение true, форма получит все KeyPress, KeyDown и KeyUp. После завершены обработчики событий формы обработки нажатия клавиши, нажатие клавиши затем назначается контроль с фокусом. Например, если для свойства KeyPreview установлено значение true и выбранный в данный момент элемент управления TextBox, после нажатия клавиши обрабатываются обработчиками событий сформировать элемент управления TextBox нажата клавиша. Обрабатывать события клавиатуры только на уровне формы и не позволять средствам управления получать события клавиатуры, установите Свойство KeyPressEventArgs.Handled в ваша форма обработчик события KeyPress правда.

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

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

E.G Пользователь нажимает клавишу K, вызываются обработчики событий форм (Key Down, Key Up, Key Pressed), а затем вызывается обработчики событий в текущем активном элементе управления.

EDIT: Нет никаких недостатков или неприятных сюрпризов. Единственное, что я могу придумать, - это очень небольшое снижение производительности, так как для каждого ключа KeyDown, KeyUp, KeyPressed необходимо проверить наличие обработчиков событий в форме. Кроме того, если вы не добавляете обработчики событий в форму и не делаете что-то, что может вызвать проблемы. вы в полном порядке. Если вам не нужно глобально обрабатывать ключевые события, кроме элементов управления, я бы предложил оставить это как false, чтобы предотвратить дополнительные проверки. На современном ПК это не будет иметь заметной разницы.

Ответ 3

Стандартная модель событий Windows заключается в том, что окно с фокусом клавиатуры получает все события клавиатуры. Помните, что в Windows все - это окно - "контроль" - это просто окно, которое является дочерним элементом другого окна. Это до этого окна, чтобы отправлять сообщения своему родителю, если он захочет сделать это, когда нажаты некоторые клавиши.

Чтобы стандартизировать навигацию между элементами управления в диалоговом окне, Windows также предоставляет "менеджер диалогов". В собственном коде для модальных диалогов это обрабатывается модальным контуром сообщения внутри функции DialogBox. Для немодальных диалогов вы должны называть IsDialogMessage внутри своего собственного цикла сообщений. Вот как он крадет клавиши Tab и курсора, чтобы перемещаться между элементами управления, и Enter, чтобы нажать кнопку по умолчанию. Это имеет противоположный эффект, не позволяя элементам управления обрабатывать Enter по умолчанию, которые обычно обрабатывают многострочные элементы управления. Чтобы узнать, хочет ли контроллер обрабатывать ключ, код менеджера диалога отправляет сфокусированное управление a WM_GETDLGCODE сообщение; если элемент управления отвечает соответствующим образом, диспетчер диалога возвращает FALSE, позволяя DispatchMessage фактически доставлять его в оконную процедуру, иначе диспетчер диалога выполняет свою собственную работу.

Windows Forms в основном просто обертывает старые собственные элементы управления, поэтому он должен соответствовать модели событий Win32. Он реализует один и тот же подход к диалоговому менеджеру - поэтому он по умолчанию не позволяет вам видеть клавиши Tab, Return и клавиши курсора.

Рекомендуемый подход, если вы хотите обработать один из этих ключей, заключается в переопределении PreviewKeyDown и установке свойства PreviewKeyDownEventArgs IsInputKey на true.

Ответ 4

Простая и тривиальная, хотя и практическая причина:

В такой игре, как Space Invaders https://www.mooict.com/c-tutorial-create-a-full-space-invaders-game-using-visual-studio/ пользователь неоднократно ударяет по пробелу, чтобы испарить инопланетян. Когда последний захватчик ушел, всплывающее текстовое поле, чтобы сказать, "хорошая работа". Пользователь все еще дергая большим пальцем, нажимает пробел (или, может быть, только освобождение буфера клавиатуры?), И поздравляющий MessageBox исчезает, прежде чем его можно прочитать. Я не мог видеть обходной путь из-за того, как формы обрабатывают нажатия кнопок/пробела.

Мой пользовательский диалог использует предварительный просмотр клавиш для предварительной обработки нажатий клавиш, отправляемых GameOverDialog, чтобы игнорировать любые нажатия пробела. Пользователь должен закрыть с помощью мыши или Enter. Это просто FixedDialog с надписью "Вы выиграли" и кнопкой [OK].

public partial class GameOverDialog : Form
{
    public GameOverDialog()
    {
        InitializeComponent();
        this.MaximizeBox = false;
        this.MinimizeBox = false;
    }

    // keyhandler keypreview = true
    private void SpaceDown(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Space)
        {
            e.Handled = true;
            return;
        }
    }

    private void SpaceUp(object sender, KeyEventArgs e)
    {
        if (e.KeyCode == Keys.Space)
        {
            e.Handled = true;
            return;
        }
    }

    private void button1_Click(object sender, EventArgs e)
    {
        this.Close();
    }
}

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