简体   繁体   English

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

[英]WinForms ComboBox SelectedIndexChanged not firing when typing few chars followed by Alt+Down

In short 简而言之

When I type a character in a ComboBox, press Alt+Down followed by Enter or Tab, the SelectedIndexChanged event doesn't fire, even though the SelectedIndex value does change! 当我在ComboBox中键入一个字符时,按Alt +向下键,然后按Enter键或Tab键,即使SelectedIndex值确实发生更改,也不会触发SelectedIndexChanged事件! Why doesn't the event fire? 为什么事件没有发生?

Update The same error occurs if you type a character, press Alt+Down and then type Esc. 更新如果键入字符,则按Alt +向下键,然后键入Esc,则会出现相同的错误。 You would expect the Esc to cancel the change. 您可能希望Esc取消更改。 However, the SelectedIndex does change, and the SelectedIndexChanged event doesn't fire. 但是,SelectedIndex 更改,并且不会触发SelectedIndexChanged事件。

What should happen if you just type Alt+Down, use the arrow keys to browse to an entry, and then type Esc? 如果只键入Alt + Down,使用箭头键浏览条目, 然后键入Esc,会发生什么? Should the selected index be set back to its original value? 是否应将所选索引设置回其原始值?


Not so short 不是那么短暂

I have a WinForm application with a ComboBox on it. 我有一个带有ComboBox的WinForm应用程序。 The ComboBox' SelectedIndexChanged event is wired up to a event handler that shows the SelectedItem in a Label control. ComboBox的SelectedIndexChanged事件连接到一个事件处理程序,该事件处理程序显示Label控件中的SelectedItem。 The ComboBox' Items collection has three values: "One", "Two", and "Three". ComboBox的Items集合有三个值:“One”,“Two”和“Three”。

  • When I select an item with the mouse, the event fires. 当我用鼠标选择项目时,事件将触发。
  • When I scroll the mouse, the event fires. 滚动鼠标时,事件会触发。
  • When I use Alt+Down to expand the combobox and walk through the items with Up and Down, the event fires. 当我使用Alt + Down扩展组合框并使用向上和向下遍历项目时,事件将触发。
  • But... When I type in the first character of a value, then press Alt+Down, followed by Enter or Tab, the value does get selected and is shown in the combobox, but the event doesn't fire. 但是......当我输入值的第一个字符时, 然后按Alt + Down,然后按Enter或Tab,值将被选中并显示在组合框中,但事件不会触发。

I've also added a button that shows the SelectedIndex. 我还添加了一个显示SelectedIndex的按钮。 It shows the SelectedIndex has changed. 它显示SelectedIndex 更改。 So even though the SelectedIndex does change, the SelectedIndexChanged event does not fire! 因此,即使SelectedIndex确实发生了变化,SelectedIndexChanged事件也不会触发!

If I just type in a valid value like One the event doesn't fire either, but in that case a click on the button reveals the SelectedIndex indeed hasn't changed. 如果我只输入一个有效值,如 One 则事件也不会触发,但在这种情况下单击按钮会显示SelectedIndex确实没有更改。 So in that case the behavior is normal. 所以在这种情况下行为是正常的。


To reproduce, create a Form and add a ComboBox, a Label and a Button. 要重现,请创建一个表单并添加一个ComboBox,一个Label和一个Button。 Place the following code in the Form1.cs: 将以下代码放在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);
        }
    }
}

I've tried several google searches in order to find a definitive answer on this but didn't find one before. 我已经尝试了几次谷歌搜索,以便找到一个明确的答案,但之前没有找到。 Just now I found a thread that actually refers to a Microsoft knowledge base article about the problem. 刚才我找到了一个线程,实际上是指有关该问题的Microsoft知识库文章。 Article KB948869 describes the problem. 文章KB948869描述了该问题。

The knowledge base article suggest to create your own combobox and override the ProcessDialogKey method. 知识库文章建议创建自己的组合框并覆盖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);
    }
}

I've tried it, but unfortunately, it doesn't seem to have any effect. 我试过了,但不幸的是,它似乎没有任何影响。 Which is a bit strange. 这有点奇怪。 I would expect a workaround described in a knowledge base article to be accurate. 我希望知识库文章中描述的解决方法是准确的。

I found another workaround though, which is to use the DropDownClosed event in stead. 我找到了另一种解决方法,即使用DropDownClosed事件代替。

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

This does seem to work, but only when using DropDownStyle.DropDown. 似乎工作,但使用DropDownStyle.DropDown时只。 When you set the DropDownStyle to DropDownList, typing a character does not fire the DropDownClosed (as there is no actual drop down in that case). 当您将DropDownStyle设置为DropDownList时,键入一个字符不会触发DropDownClosed(因为在这种情况下没有实际的下拉)。 Only if you actually open up the drop down list and select a value the DropDownClosed event is fired. 只有当您实际打开下拉列表并选择一个值时才会触发DropDownClosed事件。

So, both options are not really a good answer. 所以,这两个选项都不是一个好的答案。

Update I've even tried overriding property SelectedIndex in MyComboBox, having it call OnSelectedIndexChanged(EventArgs.Empty) . 更新我甚至尝试覆盖MyComboBox中的属性SelectedIndex,让它调用OnSelectedIndexChanged(EventArgs.Empty) After typing a character and pressing Alt+Down, the setter is executed, but it's setting the value to -1, which it already is. 键入字符并按Alt + Down后,执行setter,但它将值设置为-1,它已经是。 After pressing Tab, the setter isn't executed again, although somehow the SelectedIndex value does change. 按下Tab后,不会再次执行setter,尽管SelectedIndex值以某种方式更改。 It looks like the ComboBox is directly changing the backing field for SelectedIndex, bypassing the setting. 看起来ComboBox正在直接更改SelectedIndex的支持字段,绕过设置。 I believe something like this probably also happens in the real ComboBox. 我相信这样的事情也可能发生在真正的ComboBox中。

The appropriate DropDown property value here is DropDownList. 这里适当的DropDown属性值是DropDownList。 It doesn't have this problem. 它没有这个问题。

Coming up with a workaround for your specific problem with the DropDown style set to DropDown is quite difficult. 针对DropDown样式设置为DropDown的特定问题的解决方法非常困难。 It allows the user type arbitrary text and even a perfect match with one of the dropdown items doesn't change the SelectedIndex. 它允许用户键入任意文本,甚至与其中一个下拉项完美匹配也不会更改SelectedIndex。 You'd have to implement the Validating event and look for a match yourself. 您必须实现Validating事件并自己查找匹配项。 The DropDownClosed event would be good for your specific scenario. DropDownClosed事件对您的特定场景有用。 But really, always use DropDownList if you want perfect matches. 但实际上,如果你想完美匹配,总是使用DropDownList。

I had the ESC problem on a DropDownList-style combobox. 我在DropDownList风格的组合框中遇到了ESC问题。 I slightly modified what worked for me to accommodate your needs: 我略微修改了适合我的工作:

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

What this does is listening to keystrokes that come in while the dropdown is open. 这样做是听下拉打开时进来的击键。 If it's ESC , TAB or ENTER for a DropDown -style ComboBox or ESC for a DropDownList -style ComboBox, a SelectedIndexChanged -Event is triggered when the DropDown is closed. 如果是ESC,TAB输入一个DropDown式的组合框或ESCDropDownList风格的组合框,一个SelectedIndexChanged当下拉关闭-活动被触发。
I have never ever used ComboBoxStyle.Simple and don't really know how it does or should work, but since it to the best of my knowledge never displays a DropDown, this should be safe even for that style. 我从来没有使用过ComboBoxStyle.Simple ,也不知道它是如何工作的,但是因为据我所知,它永远不会显示DropDown,即使对于那种风格也应该是安全的。

If you don't want to derive from ComboBox to build your own control, you can also apply similar logic to a ComboBox on a form by subscribing to it's PreviewKeyDown and DropDownClosed events. 如果您不想从ComboBox派生来构建自己的控件,您还可以通过订阅它的PreviewKeyDownDropDownClosed事件将类似的逻辑应用于表单上的ComboBox。

Correct me if I'm wrong. 如我错了请纠正我。 Here is code I've used. 这是我用过的代码。

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

I ended up deriving my own class from ComboBox: 我最终从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);
    }
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 使用jQuery组合框时不触发SelectedIndexChanged - Not firing the SelectedIndexChanged when using jquery combobox ComboBox SelectedIndexChanged 事件未触发 - ComboBox SelectedIndexChanged event not firing SelectedIndexChanged不触发ComboBox - SelectedIndexChanged not firing for the ComboBox 以编程方式选择索引0(从-1)时,组合框未触发SelectedIndexChanged - Combobox not firing SelectedIndexChanged when programmatically selecting index 0 (from -1) 为Winform中的组合框选择OwnerDrawFixed模式时,不会触发SelectedIndexChanged事件 - SelectedIndexChanged event is not firing when OwnerDrawFixed mode selected for Combobox in Winform 填充时如何防止ComboBox触发另一个ComboBox的SelectedIndexChanged事件 - How to prevent a ComboBox from firing another ComboBox's SelectedIndexChanged event when filling it 在运行时生成的控件的WinForms中未触发SelectedIndexChanged - SelectedIndexChanged Not Firing in WinForms for Controls Generated at Runtime WinForms comboBox_SelectedValueChanged在tabControl_SelectedIndexChanged上触发了三次 - WinForms comboBox_SelectedValueChanged fired thrice on tabControl_SelectedIndexChanged Winforms:哪个事件要触发? combobox.selectedindexchanged或bindingsource.currentchanged - Winforms: Which event to fire? combobox.selectedindexchanged OR bindingsource.currentchanged winforms组合框,如何在获得焦点时阻止其下降 - winforms combobox, how to stop it from dropping down when getting focus
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM