这是一个简短的程序,可以重现我刚刚遇到的问题。这是在带有.NET 4.0的MS Windows 7下编译的,以防万一有所不同。
using System;
using System.Drawing;
using System.Windows.Forms;
// Compile with "csc /target:exe /out:comboboxbug.exe /r:System.dll /r:System.Drawing.dll /r:System.Windows.Forms.dll comboboxbug.cs"
// in a Visual Studio command prompt.
static class Program
{
[STAThread]
static void Main()
{
//Create a label.
Label oLabel = new Label();
oLabel.Location = new Point (10, 10);
oLabel.Size = new Size (100, 15);
oLabel.Text = "Combo box bug:";
// Create a combo-box.
ComboBox oComboBox = new ComboBox();
oComboBox.Location = new Point (10, 50);
oComboBox.Size = new Size (150, 21);
oComboBox.Items.AddRange (new object[]
{ "A", "A B", "A C", "A B C", "A C B", "A B C D", "A C B D" });
oComboBox.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
oComboBox.AutoCompleteSource = AutoCompleteSource.ListItems;
oComboBox.SelectionChangeCommitted
+= new EventHandler (comboBox_SelectionChangeCommitted);
// Create a form.
Form oForm = new Form();
oForm.Size = new Size (200, 150);
oForm.Controls.Add (oLabel);
oForm.Controls.Add (oComboBox);
// Run this form.
Application.Run (oForm);
}
static void comboBox_SelectionChangeCommitted (object sender,
EventArgs e)
{
MessageBox.Show ("SelectionChangeCommitted");
}
}
单击组合框的文本部分,然后键入“A”。您将获得自动填充建议列表。用鼠标单击其中一个选项。 SelectionChangeCommitted
事件不会发生!
选择菜单项而不使用自动完成功能。您将看到一个消息框,显示SelectionChangeCommitted
事件已发生!
鉴于用户在两种情况下都改变了选择,在两种情况下都不应该调用SelectionChangeCommitted
吗?
使用SelectedIndexChanged
事件不是一个选项,因为对于这个固定示例背后的应用程序,我只希望它在用户进行选择时发生,而不是在以编程方式设置时。
答案 0 :(得分:3)
使用
SelectedIndexChanged
事件不是一个选项,因为对于这个固定示例背后的应用程序,我只希望它在用户进行选择时发生,而不是在以编程方式设置时。
您还可以通过编写包装器方法来更改暂时禁用事件的选择来完成此操作。
不幸的是,我不知道解决SelectionChangeCommitted
未针对更一般情况(例如您不控制ComboBox
或如何访问)的问题的解决方案
编辑:
我为ComboBox调用的所有事件制作了一个流光,并且似乎没有任何其他事件可以执行您要查找的内容。我能想到的唯一解决方案是涉及到AutoComplete触发的事件。困难在于知道这些事件是什么,因为它们似乎没有触发我的次要测试所显示的ComboBox
。
答案 1 :(得分:1)
仅供参考,这是我提出的最佳解决方案。显然,这是ComboBox子类上的Leave事件处理程序。在鼠标单击时不会发生SelectionChangeCommitted事件,但至少它发生在GUI交互的正常流程中。
private void this_Leave (object sender, EventArgs e)
{
// If this is an autocomplete combo-box, select the
// item that was found by autocomplete.
// This seems like something that ComboBox should be
// doing automatically...I wonder why it doesn't?
if (this.AutoCompleteMode != AutoCompleteMode.None)
{
// Determine which combo-box item matches the text.
// Since IndexOf() is case-sensitive, do our own
// search.
int iIndex = -1;
string strText = this.Text;
ComboBox.ObjectCollection lstItems = this.Items;
int iCount = lstItems.Count;
for (int i = 0; i < iCount; ++i)
{
string strItem = lstItems[i].ToString();
if (string.Compare (strText, strItem, true) == 0)
{
iIndex = i;
break;
}
}
// If there's a match, and this isn't already the
// selected item, make it the selected item.
//
// Force a selection-change-committed event, since
// the autocomplete was driven by the user.
if (iIndex >= 0
&& this.SelectedIndex != iIndex)
{
this.SelectedIndex = iIndex;
OnSelectionChangeCommitted (EventArgs.Empty);
}
}
}
答案 2 :(得分:0)
如果有人遇到这个问题,我建议一个对我有用的解决方案......
请与我联系,接受组合框的建议,通常用户需要使用Enter键进行键入。
您可以写入Combo-box属性的KeyDown事件,如下所示:
private void cboProperty_SelectionChangeCommitted(object sender, EventArgs e)
{
//Call here the event of SelectionChangeCommitted
cboProperty_SelectionChangeCommitted(sender,null);
}
它会在正确的时间提升SelectionChangeCommitted。
答案 3 :(得分:0)
此变通办法对我来说很好,对您也希望如此。当通过在组合框中键入数据来使用自动完成功能以通过键盘或鼠标选择获取项目时,您需要_KeyDown事件。从内部调用_SelectionChangeCommitted方法,该方法包含其他操作的代码。参见下面的代码:
private void YourComboBox_KeyDown(object sender, KeyEventArgs e)
{
//Works also when user select and click on autocomplete list.
if (e.KeyCode == Keys.Enter && YourComboBox.SelectedItem != null)
YourComboBox_SelectionChangeCommitted(sender, e);
}
答案 4 :(得分:0)
对于上述非自动完成案例(即我的2020年10月28日修改),Leave
子类上的此ComboBox
事件处理程序合并了新案例和旧案例一个,只要您的SelectionChangeCommitted
事件处理程序为idempotent。与我之前的答案相比,它删除了自动完成测试,并始终调用OnSelectionChangeCommitted()
。
private void this_Leave (object sender, EventArgs e)
{
// Determine which combo-box item matches the text.
// Since IndexOf() is case-sensitive, do our own
// search.
int iIndex = -1;
string strText = this.Text;
ComboBox.ObjectCollection lstItems = this.Items;
int iCount = lstItems.Count;
for (int i = 0; i < iCount; ++i)
{
string strItem = lstItems[i].ToString();
if (string.Compare (strText, strItem, true) == 0)
{
iIndex = i;
break;
}
}
// If there's a match, and this isn't already the
// selected item, make it the selected item.
if (iIndex >= 0
&& this.SelectedIndex != iIndex)
this.SelectedIndex = iIndex;
// Force a selection-change-committed event, since
// the autocomplete was driven by the user.
OnSelectionChangeCommitted (EventArgs.Empty);
}