[英]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”。
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
式的组合框或ESC的DropDownList
风格的组合框,一个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
派生来构建自己的控件,您还可以通过订阅它的PreviewKeyDown
和DropDownClosed
事件将类似的逻辑应用于表单上的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.