C# WinForms组合框SelectedIndexChanged在键入几个字符并后跟Alt+;向下

C# WinForms组合框SelectedIndexChanged在键入几个字符并后跟Alt+;向下,c#,winforms,events,combobox,C#,Winforms,Events,Combobox,简言之 在组合框中键入字符时,按Alt+Down,然后按Enter或Tab,即使SelectedIndex值发生更改,SelectedIndexChanged事件也不会触发!为什么活动没有启动 更新 如果键入字符,按Alt+Down,然后键入Esc,则会发生相同的错误。您可能希望Esc取消更改。但是,SelectedIndex确实会更改,并且SelectedIndexChanged事件不会触发 如果只需键入Alt+Down,使用箭头键浏览到某个条目,然后键入Esc,会发生什么情况?是否应将所选索

简言之

在组合框中键入字符时,按Alt+Down,然后按Enter或Tab,即使SelectedIndex值发生更改,SelectedIndexChanged事件也不会触发!为什么活动没有启动

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

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


不要太短

我有一个WinForm应用程序,上面有一个组合框。组合框的SelectedIndexChanged事件连接到一个事件处理程序,该事件处理程序在Label控件中显示SelectedItem。ComboBox的Items集合有三个值:“一”、“二”和“三”

  • 当我用鼠标选择一个项目时,事件触发
  • 当我滚动鼠标时,事件触发
  • 当我使用Alt+Down展开组合框并使用Up和Down遍历项目时,会触发事件
  • 但是。。。当我键入值的第一个字符,然后按Alt+Down,然后按Enter或Tab时,该值会被选中并显示在组合框中,但不会触发事件
我还添加了一个显示SelectedIndex的按钮。它显示所选索引已更改。因此,即使SelectedIndex发生更改,SelectedIndexChanged事件也不会触发

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


要复制,请创建一个表单并添加一个组合框、一个标签和一个按钮。将以下代码放入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);
        }
    }
}

此处适当的下拉属性值为DropDownList。它没有这个问题


对于下拉样式设置为DropDown的特定问题,很难找到解决方法。它允许用户输入任意文本,即使与其中一个下拉项完全匹配,也不会更改SelectedIndex。您必须实现验证事件并自己寻找匹配项。DropDownClosed事件适合您的特定场景。但实际上,如果你想要完美的匹配,一定要使用DropDownList。

为了找到一个明确的答案,我尝试了几次谷歌搜索,但之前没有找到。刚才我发现一个线程实际上引用了一篇关于这个问题的Microsoft知识库文章。文章描述了这个问题

知识库文章建议您创建自己的组合框并重写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);
    }
}
我试过了,但不幸的是,它似乎没有任何效果。这有点奇怪。我希望知识库文章中描述的解决方法是准确的

不过,我找到了另一种解决方法,那就是使用DropDownClosed事件代替

private void comboBox1_DropDownClosed(object sender, EventArgs e)
{
    label1.Text = "DroDownClosed Selected index: " + comboBox1.SelectedIndex;
}
这似乎确实有效,但只有在使用DropDownStyle.DropDown时才有效。将DropDownStyle设置为DropDownList时,键入字符不会触发DropDownClosed(因为在这种情况下没有实际的下拉)。仅当您实际打开下拉列表并选择一个值时,才会触发DropDownClosed事件

因此,这两种选择都不是一个好答案

更新
我甚至尝试在MyComboBox中重写属性SelectedIndex,让它调用SelectedIndexChanged(EventArgs.Empty)。在键入一个字符并按下Alt+Down键后,setter将被执行,但它正在将值设置为-1,而它已经设置为-1。按Tab键后,setter不会再次执行,尽管SelectedIndex值确实会发生变化。看起来ComboBox绕过设置直接更改SelectedIndex的支持字段。我相信在真正的组合框中也可能发生类似的情况。

如果我错了,请纠正我。这是我用过的代码

comboBox1.Items.AddRange(new object[] {
                "One",
                "Two",
                "Three"
});

comboBox1.SelectedIndexChanged+=(sa,ea)=>
 {
   label1.Text = "Selected index: " + comboBox1.SelectedIndex;
 };
comboBox1.TextChanged+= (sa, ea) =>
 {
 comboBox1.SelectedIndex = comboBox1.FindStringExact(comboBox1.Text);

 //OR
 //comboBox1.SelectedIndex = comboBox1.Items.IndexOf(comboBox1.Text);
  comboBox1.SelectionStart  = comboBox1.Text.Length;
};
我在DropDownList样式的组合框上遇到了ESC问题。为了满足您的需求,我稍微修改了适合我的内容:

public class MyComboBox : System.Windows.Forms.ComboBox
{
  private bool _sendSic;

  protected override void OnPreviewKeyDown(System.Windows.Forms.PreviewKeyDownEventArgs e)
  {
    base.OnPreviewKeyDown(e);

    if (DroppedDown)
    {
      switch(e.KeyCode)
      {
        case System.Windows.Forms.Keys.Escape:
          _sendSic = true;
          break;
        case System.Windows.Forms.Keys.Tab:
        case System.Windows.Forms.Keys.Enter:
          if(DropDownStyle == System.Windows.Forms.ComboBoxStyle.DropDown)
            _sendSic = true;
          break;
      }
    }
  }

  protected override void OnDropDownClosed(System.EventArgs e)
  {
    base.OnDropDownClosed(e);

    if(_sendSic)
    {
      _sendSic = false;
      OnSelectedIndexChanged(System.EventArgs.Empty);
    }
  }
}
这样做的目的是在下拉菜单打开时听到输入的击键。如果是ESC、TAB或ENTER键用于
下拉列表
-样式组合框或ESC键用于
下拉列表
-样式组合框,则关闭下拉列表时会触发
SelectedIndexChanged
-事件。
我从未使用过
ComboBoxStyle.Simple
,也不知道它是如何工作的,但就我所知,它从来没有显示过下拉列表,因此即使对于那种样式,这也应该是安全的


如果您不想从
ComboBox
派生来构建自己的控件,也可以通过订阅表单上的ComboBox的
PreviewKeyDown
DropDownClosed
事件,将类似的逻辑应用于该ComboBox

public class EditableComboBox : ComboBox
{
    protected int backupIndex;
    protected string backupText;

    protected override void OnDropDown(EventArgs e)
    {
        backupIndex = this.SelectedIndex;
        if (backupIndex == -1) backupText = this.Text;
        else backupText = null;
        base.OnDropDown(e);
    }

    protected override void OnSelectionChangeCommitted(EventArgs e)
    {
        backupIndex = -2;
        base.OnSelectionChangeCommitted(e);
    }

    protected override void OnSelectionIndexChanged(EventArgs e)
    {
        backupIndex = -2;
        base.OnSelectionIndexChanged(e);
    }

    protected override void OnDropDownClosed(EventArgs e)
    {
        if (backupIndex > -2 && this.SelectedIndex != backupIndex)
        {
            if (backupIndex > -1)
            {
                this.SelectedIndex = backupIndex;
            }
            else
            {
                string oldText = backupText;
                this.SelectedIndex = -1;
                this.Text = oldText;
                this.SelectAll();
            }
        }
        base.OnDropDownClosed(e);
    }
}

我发现了同样的问题,所以我处理了TextChanged事件。根据MSDN页面-SelectedIndexChanged事件将在SelectedIndex属性的值更改时触发。@adatapost:我在这里描述事情的方式(键入第一个字符,然后Alt+Down),然后单击按钮)表明SelectedIndex确实更改。我的情况不是用户在完整条目中键入,只需输入第一个字符,然后按Alt+Down键。正如我的按钮所显示的,这样它确实改变了SelectedIndex。这正是让我吃惊的地方。SelectedIndex确实会更改,但事件不会触发。是的,很遗憾,不是吗?我的观点是,除非将下拉样式设置为DropDownList,否则永远不能依赖SelectedIndex。你试过了吗?是的,我试过了。但通过使用下拉式,它不再是一个真正的组合框。