【问题标题】:Forms not responding to KeyDown events表单不响应 KeyDown 事件
【发布时间】:2023-03-27 13:50:01
【问题描述】:

我已经在我的 Windows 窗体项目上工作了一段时间,我决定尝试使用键盘快捷键。经过一番阅读,我想我只需要编写一个事件处理程序并将其绑定到表单的 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 事件?

【问题讨论】:

    标签: c# .net winforms


    【解决方案1】:

    您的表单是否将 KeyPreview 属性设置为 true?

    Form.KeyPreview 属性

    获取或设置一个值,该值指示表单是否将接收密钥 事件传递给具有焦点的控件之前的事件。

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

    【讨论】:

    • 这是一个 hack,可以让 VB6 程序员开心。它存在执行顺序问题,请改写 ProcessCmdKey()。
    • @HansPassant,我找不到任何解释执行顺序问题的内容。 KeyDown + KeyPreview 看不到所有的key,问题就够了,但是执行顺序有什么问题呢?
    • 有很多覆盖来检测快捷键。按顺序执行,KeyPreview + KeyDown最后死了。
    【解决方案2】:

    在 StackOverflow 和 MSDN12(包括此处接受的答案)上针对此问题最常见的建议是快速而简单的:

    只要FormKeyPreview 属性设置为true,就会在Form 上触发KeyDown 事件

    这对于大多数目的来说已经足够了,但由于两个原因它存在风险:

    1. KeyDown 处理程序 do not see all keys。具体来说,“您看不到用于导航的击键类型。例如光标键和 Tab、Escape 和 Enter 用于对话框。”

    2. 有几种不同的方法可以拦截关键事件,它们都是按顺序发生的。 KeyDown 被处理最后。因此,KeyPreview 并不是一个预览,而且活动可能会在途中的几站被静音。

    (这些积分归功于@HansPassant。)

    改为在您的Form 中覆盖ProcessCmdKey

    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 事件,而不是像在KeyDown 事件处理程序中那样将KeyPressEventArgs.Handled 设置为trueHere 是一篇更详细的文章。

    【讨论】:

    • 这是正确的答案,尤其是当您发现在 KeyPreview 设置为 true 时 PreviewKeyDown 根本不会触发。
    【解决方案3】:

    尝试将表单上的KeyPreview 属性设置为true。这对我注册按键很有用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2011-06-10
      • 1970-01-01
      • 1970-01-01
      • 2012-10-29
      • 1970-01-01
      • 1970-01-01
      • 2023-03-14
      相关资源
      最近更新 更多