如何防止控件在模式窗体打开时捕获 KeyDown 事件? [英] How to prevent controls from capturing KeyDown events while a modal form is open?

查看:25
本文介绍了如何防止控件在模式窗体打开时捕获 KeyDown 事件?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个带有 CancelButton 和 AcceptButton(名为 btnCancel 和 btnOK)的表单.我有一些组合框作为输入字段.

I have a form with CancelButton and AcceptButton (named btnCancel and btnOK). And I have some ComboBoxes as input fields.

ComboBox 阻止我的 AcceptButton 和 CancelButton 接收 Escape 和 Enter 键,因此我将此代码添加到所有字段的 KeyDown 事件中:

ComboBoxes prevent my AcceptButton and CancelButton to receive Escape and Enter keys, so I added this code to KeyDown event for all fields:

if (e.KeyData == Keys.Escape)
{
    ComboBox field = (ComboBox)sender;
    if ((field.DropDownStyle == ComboBoxStyle.Simple) || (!field.DroppedDown))
    {
        e.SuppressKeyPress = true;
        btnCancel.PerformClick();
    }
}
else if (e.KeyData == Keys.Enter)
{
    ComboBox field = (ComboBox)sender;
    if ((field.DropDownStyle == ComboBoxStyle.Simple) || (!field.DroppedDown))
    {
        e.SuppressKeyPress = true;
        btnOK.PerformClick();
    }
}

这是OK按钮的Clicked事件中的代码:

This is the code in Clicked event of OK button:

if (!changesAreSaved)
{
    SaveChangesToNode();
}

List<int> invalidIndices = ValidateAndRefineNodes(true);

if (invalidIndices.Count == 0)
{
    this.DialogResult = DialogResult.OK;
    this.Close();
}
else
{
    MessageBox.Show(this, "Enter correct values for all fields before you press OK.", "Cannot Save Information",
        MessageBoxButtons.OK, MessageBoxIcon.Error);
}

一切正常,但是当 ComboBox 具有焦点并且我按下键盘上的 Enter 键时,btnOK_Clicked 再次在显示其 MessageBox 时调用 Fields_KeyDown(在 if 的其他部分).就在 MessageBox.Show(...) 被调用之后,KeyDown 事件被第二次无故调用.

Everything is OK but when a ComboBox has Focus and I press Enter key on my keyboard, btnOK_Clicked calls Fields_KeyDown again only when it shows its MessageBox (on else part of if). Exactly right after MessageBox.Show(...) is being called, KeyDown event is being called for second time without any reason.

这是第一次调用的调用栈:

This is Call Stack for first call:

这是第二个:

根本不应发生第二次调用.在第二个调用堆栈中,第一个 btnOK_Click(第三行)再次从 MessageBox.Show(...) 调用 Fields_KeyDown(第二行).这怎么可能?我很困惑...

Second call should not occur at all. In second Call Stack, first btnOK_Click (third line) again calls Fields_KeyDown (second line) from MessageBox.Show(...). How is this possible? I'm confused...

第二次调用的调用堆栈,外部代码可见:

Call Stack for second call with External Code visible:

推荐答案

您无法正确处理 KeyDown 事件中的 Escape 和 Enter 键,因为它们是在键盘预处理阶段处理的 - Control.IsInputKeyControl.ProcessDialogKey.通常控件会为您执行此操作,但是当 DropDownStyleSimple 时,ComboBox 实现中似乎存在错误.

You cannot correctly process Escape and Enter key in KeyDown event because they are handled during the keyboard preprocessing phase - Control.IsInputKey and Control.ProcessDialogKey. Normally controls do that for you, but looks like there is a bug in ComboBox implementation when DropDownStyle is Simple.

要获得所需的行为,请像这样创建和使用您自己的 ComboBox 子类

To get the desired behavior, create and use your own ComboBox subclass like this

public class MyComboBox : ComboBox
{
    protected override bool IsInputKey(Keys keyData)
    {
        if (DropDownStyle == ComboBoxStyle.Simple)
        {
            switch (keyData & (Keys.KeyCode | Keys.Alt))
            {
                case Keys.Return:
                case Keys.Escape:
                    return false;
            }
        }
        return base.IsInputKey(keyData);
    }
}

附言当然不要忘记删除您的 KeyDown 事件处理程序.

P.S. And of course don't forget to remove your KeyDown event handlers.

这篇关于如何防止控件在模式窗体打开时捕获 KeyDown 事件?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆