如何在模态窗体打开时阻止控件捕获KeyDown事件?

时间:2015-12-01 12:57:55

标签: c# winforms combobox keydown

我有一个带有CancelButton和AcceptButton的表单(名为btnCancel和btnOK)。我有一些ComboBoxes作为输入字段。

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

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事件中的代码:

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有Focus并且我按下键盘上的Enter键时,btnOK_Clicked在显示其MessageBox(在if的其他部分)时再次调用Fields_KeyDown 。正好在调用MessageBox.Show(...)之后,第二次调用KeyDown事件而没有任何理由。

这是第一次通话的呼叫堆栈:

This is Call Stack for first call

这是第二次:

This is Call Stack for second call

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

呼叫堆栈以进行第二次呼叫,外部代码可见:

Call Stack with External Code visible

2 个答案:

答案 0 :(得分:1)

虽然我不知道这种行为背后的主要原因。

但在这种情况下,显然KeyDown事件会触发2次。 (设置一个断点,你会看到。)

由于您需要在代码中处理它,您可以尝试忽略 Enter 键之一:

bool handled = true;
private void comboBox1_KeyDown(object sender, KeyEventArgs e)
{
    if (e.KeyCode == Keys.Enter)
    {
        /*Prevent handling the Enter key twice*/
        handled = !handled;
        if(handled)
            return;

        //Rest of logic
        //OkButton.PerformClick();
    }
}

答案 1 :(得分:1)

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

要获得所需的行为,请创建并使用您自己的ComboBox子类,如下所示

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);
    }
}

P.S。当然不要忘记删除KeyDown事件处理程序。