WinForms ComboBox SelectedIndexChanged在键入少量字符后跟Alt + Down时不触发

com*_*cme 13 c# events combobox winforms

简而言之

当我在ComboBox中键入一个字符时,按Alt +向下键,然后按Enter键或Tab键,即使SelectedIndex值确实更改,也不会触发SelectedIndexChanged事件!为什么事件没有发生?

更新 如果键入字符,则按Alt +向下键,然后键入Esc,则会出现相同的错误.您可能希望Esc取消更改.但是,SelectedIndex 更改,并且不会触发SelectedIndexChanged事件.

如果只键入Alt + Down,使用箭头键浏览条目,然后键入Esc,会发生什么?是否应将所选索引设置回其原始值?


不是那么短暂

我有一个带有ComboBox的WinForm应用程序.ComboBox的SelectedIndexChanged事件连接到一个事件处理程序,该事件处理程序显示Label控件中的SelectedItem.ComboBox的Items集合有三个值:"One","Two"和"Three".

  • 当我用鼠标选择项目时,事件将触发.
  • 滚动鼠标时,事件会触发.
  • 当我使用Alt + Down扩展组合框并使用向上和向下遍历项目时,事件将触发.
  • 但是......当我输入值的第一个字符时,然后按Alt + Down,然后按Enter或Tab,值将被选中并显示在组合框中,但事件不会触发.

我还添加了一个显示SelectedIndex的按钮.它显示SelectedIndex 更改.因此,即使SelectedIndex确实发生了变化,SelectedIndexChanged事件也不会触发!

如果我只输入一个有效的值,就像 One 事件不会触发一样,但在这种情况下点击按钮会显示SelectedIndex确实没有改变.所以在这种情况下行为是正常的.


要重现,请创建一个表单并添加一个ComboBox,一个Label和一个Button.将以下代码放在Form1.cs中:

using System;
using System.Windows.Forms;

namespace ComboBoxSelectedIndexChanged
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            comboBox1.Items.AddRange(new object[] {
                "One",
                "Two",
                "Three"
            });
        }

        private void comboBox1_SelectedIndexChanged(object sender, EventArgs e)
        {
            label1.Text = "Selected index: " + comboBox1.SelectedIndex;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            MessageBox.Show("Selected item: " + comboBox1.SelectedItem +
                "\nSelected index: " + comboBox1.SelectedIndex);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

com*_*cme 6

我已经尝试了几次谷歌搜索,以便找到一个明确的答案,但之前没有找到.刚才我找到了一个线程,实际上是指有关该问题的Microsoft知识库文章.文章KB948869描述了该问题.

知识库文章建议创建自己的组合框并覆盖ProcessDialogKey方法.

using System.Windows.Forms;

public class MyComboBox : ComboBox
{
    protected override bool ProcessDialogKey(Keys keyData)
    {
        if (keyData == Keys.Tab)
            this.DroppedDown = false;
        return base.ProcessDialogKey(keyData);
    }
}
Run Code Online (Sandbox Code Playgroud)

我试过了,但不幸的是,它似乎没有任何影响.这有点奇怪.我希望知识库文章中描述的解决方法是准确的.

我找到了另一种解决方法,即使用DropDownClosed事件代替.

private void comboBox1_DropDownClosed(object sender, EventArgs e)
{
    label1.Text = "DroDownClosed Selected index: " + comboBox1.SelectedIndex;
}
Run Code Online (Sandbox Code Playgroud)

似乎工作,但使用DropDownStyle.DropDown时只.当您将DropDownStyle设置为DropDownList时,键入一个字符不会触发DropDownClosed(因为在这种情况下没有实际的下拉).只有当您实际打开下拉列表并选择一个值时才会触发DropDownClosed事件.

所以,这两个选项都不是一个好的答案.

更新 我甚至尝试覆盖MyComboBox中的属性SelectedIndex,让它调用OnSelectedIndexChanged(EventArgs.Empty).键入字符并按Alt + Down后,执行setter,但它将值设置为-1,它已经是.按下Tab后,不会再次执行setter,尽管SelectedIndex值以某种方式更改.看起来ComboBox正在直接更改SelectedIndex的支持字段,绕过设置.我相信这样的事情也可能发生在真正的ComboBox中.


Han*_*ant 5

这里适当的DropDown属性值是DropDownList.它没有这个问题.

针对DropDown样式设置为DropDown的特定问题的解决方法非常困难.它允许用户键入任意文本,甚至与其中一个下拉项完美匹配也不会更改SelectedIndex.您必须实现Validating事件并自己查找匹配项.DropDownClosed事件对您的特定场景有用.但实际上,如果你想完美匹配,总是使用DropDownList.

  • 我不得不建议你实现自己的ComboBox控件,这样你就可以按照你想要的方式工作.下拉列表有点棘手,它是一个顶级窗口.让常规用户在早期使用您的版本,程序员和用户往往有非常不同的需求.一个普遍的用户愿望是"让它像我使用的任何其他程序一样工作".他们在这方面有点陷入泥潭. (4认同)
  • 是的,伤心不是吗?我的观点是,除非将DropDown样式设置为DropDownList,否则永远不能依赖SelectedIndex.你试过吗? (2认同)