Недостаток настройки Form.KeyPreview = true?
Интересно, для чего на самом деле подходит свойство Form.KeyPreview? Почему он существует и чем я "рискую", устанавливая его в true? Я предполагаю, что это должно иметь какой-то негативный эффект - иначе он вообще не должен существовать (или, по крайней мере, быть истинным по умолчанию)?
РЕДАКТИРОВАТЬ: я прекрасно знаю, что он делает. Я спрашиваю почему. Почему я должен установить его в значение true, чтобы вызвать события клавиатуры? Почему события клавиатуры не всегда запускаются для формы. Что не только это стандартное поведение?
Конкретная причина, по которой я спрашиваю: я только что установил KeyPreview = true в базовой форме моего приложения, от которой наследуются все остальные формы. Я готовлюсь к неприятному сюрпризу?
3 ответа
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
Истина не вызывает проблем. Форма KeyDown
Событие будет запущено, оно будет иметь влияние, только если у него есть код, который что-то делает с нажатием клавиши. Но имейте в виду, что он внимательно следит за использованием VB6, вы не можете увидеть, какие нажатия клавиш используются для навигации. Как и клавиши курсора и Tab
, Escape
а также Enter
для диалога. Не проблема с ProcessCmdKey()
,
Из MSDN
Если для этого свойства установлено значение true, форма будет получать все события KeyPress, KeyDown и KeyUp. После того, как обработчики событий формы завершили обработку нажатия клавиши, нажатие клавиши затем назначается элементу управления с фокусом. Например, если для свойства KeyPreview установлено значение true, а текущий выбранный элемент управления является TextBox, после того, как нажатие клавиши обработано обработчиками событий формы, элемент управления TextBox получит нажатую клавишу. Чтобы обрабатывать события клавиатуры только на уровне формы и не разрешать элементам управления получать события клавиатуры, установите для свойства KeyPressEventArgs.Handled в обработчике событий KeyPress формы значение true.
Вы можете использовать это свойство для обработки большинства нажатий клавиш в вашем приложении и либо обрабатывать нажатие клавиш, либо вызывать соответствующий элемент управления для обработки нажатий клавиш. Например, когда приложение использует функциональные клавиши, вы можете захотеть обрабатывать нажатия клавиш на уровне формы, а не писать код для каждого элемента управления, который может получать события нажатия клавиш.
По сути, когда вы устанавливаете значение true, ваша форма может обрабатывать ключевые события, а также элементы управления.
EG Пользователь нажимает клавишу K, вызывается обработчик событий формы (Key Down, Key Up, Key Pressed), а затем вызываются обработчики событий в текущем активном элементе управления.
РЕДАКТИРОВАТЬ: Нет, нет никаких недостатков или неприятных сюрпризов. Единственное, о чем я могу подумать, это очень небольшое снижение производительности, так как нужно проверять дескрипторы событий в форме для каждого KeyDown,KeyUp, KeyPressed. Кроме того, если вы не добавляете обработчики событий в форму и делаете что-то, что может вызвать проблемы. ты в порядке Если вам не нужно глобально обрабатывать ключевые события, кроме элементов управления, я бы посоветовал вам оставить это как ложное, чтобы избежать дополнительных проверок. На современных ПК это не будет заметно.
Стандартная модель событий Windows состоит в том, что окно с фокусом клавиатуры получает все события клавиатуры. Помните, что в Windows все является окном - "элемент управления" - это просто окно, являющееся дочерним элементом другого окна. Это до того окна, чтобы запускать сообщения своему родителю, если он решит сделать это, при нажатии определенных клавиш.
Для стандартизации навигации между элементами управления в диалоговом окне Windows также предоставляет "диспетчер диалогов". В нативном коде для модальных диалогов это обрабатывается модальным циклом сообщений внутри DialogBox
функция. Для немодальных диалогов вы должны позвонить IsDialogMessage
в вашем собственном цикле сообщений. Вот как он крадет клавиши Tab и курсора, чтобы перемещаться между элементами управления, и Enter, чтобы нажать кнопку по умолчанию. Это имеет противоположный эффект - не позволяет элементам управления обрабатывать Enter по умолчанию, что обычно обрабатываются элементами управления многострочным редактированием. Чтобы выяснить, хочет ли элемент управления обрабатывать ключ, код диспетчера диалогов посылает сфокусированному элементу управления WM_GETDLGCODE
сообщение; если элемент управления отвечает соответствующим образом, менеджер диалогов возвращает FALSE
позволяющий DispatchMessage
фактически доставить его в оконную процедуру, в противном случае менеджер диалогов делает свое дело.
Windows Forms в основном просто оборачивает старые собственные элементы управления, поэтому он должен соответствовать модели событий Win32. Он реализует тот же подход диспетчера диалогов - следовательно, по умолчанию он не позволяет вам видеть Tab, Return и клавиши курсора.
Рекомендуемый подход, если вы хотите обработать один из этих ключей, это переопределить PreviewKeyDown
и установить PreviewKeyDownEventArgs
IsInputKey
собственность на true
,
Простая и тривиальная, хотя и практическая причина:
В такой игре, как 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] или любую форму, которая позволяет предварительный просмотр ключа.