我使用了KeyDown事件和一些简单的代码,例如if (e.KeyCode == Keys.F1)
来捕获在表单上按下F1键,但如果在表单上有一些文本框或者有一些使用Dock Fill 的电子表格,那么以上代码将变得无用并且不起作用。但是我想要在用户按下此表单上的F1键时执行某些操作。那么我们如何能够捕获整个表单上的特定按键事件,例如F1? 我不想走捕获表单上所有其他控件的KeyDown事件并将它们传递给表单进行处理的路线。是否有更加干净的方法来做到这一点?
是的,确实有方法。无论当前具有输入焦点的控件是什么,处理关键事件的表单正确的方式是覆盖表单类的ProcessCmdKey
方法:
protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
{
if (keyData == Keys.F1)
{
MessageBox.Show("You pressed the F1 key");
return true; // indicate that you handled this keystroke
}
// Call the base class
return base.ProcessCmdKey(ref msg, keyData);
}
你需要返回true
来表明你已处理了按键并且不希望将其传递给其他控件。如果你希望将其传递给其他控件的事件处理程序,只需返回false
。
最好忽略KeyPreview
属性。这是VB 6时代的陈旧之物,不是.NET世界中首选的方式。更多阅读:设置Form.KeyPreview = true有什么缺点?
将表单的KeyPreview
设置为true。这将确保表单首先获取按键消息,如果您处理它,可以设置e.Handled = true
,以便它不会传递到控件。
开启KeyPreview
后,表单中的每个按键都会先通过它的键事件处理程序进行路由。
KeyPreview
利用了.NET的事件中心架构,而您只是覆盖了WndProc
,这是Win3.1(没错,就是1992年的技术)首选的方法。 - BlindyWndProc
也可以实现,但这并不是完全相同的事情。框架会在适当的时候专门调用此方法来处理这些事件。此外,以这种方式处理事件允许您决定是否要将事件传递给其他控件。 - Cody GrayuMsg=WM_KEYDOWN
时覆盖WndProc
和检查 Win32 API 中的虚拟键代码一样。而且,就像检查 Win32 API 中的虚拟键代码一样,您不知道用户输入的是实际键还是其移位版本(以及其他内容)。各有所好,但我会更加小心地选择调用哪个API。 - BlindyKeyPreview
是更好的选择。 - Cody Gray