使用DropDown样式可靠地选择ComboBox中的项目

时间:2013-11-07 00:08:49

标签: c# .net winforms combobox

我的WinForms应用程序中有ComboBox具有DropDown样式,或者换句话说,它允许用户键入值,或者从下拉列表中选择它。它看起来像这样:

enter image description here

我的目标是根据索引从下拉列表中选择一个项目。所以我这样做:

//I know for sure that i >= 0 && i < comboBox.Items.Count
comboBox.SelectedIndex = i;  //i = index of the existing item

这很好用,除非上面一行之后我显示一条消息:

MessageBox.Show("Error");

在这种情况下,在我在此计算机上进行测试期间,组合框中的项目大致在80%的时间内被选中。所以这里显然存在一些时间问题。

我需要知道的是选择ComboBox项目的“确定”方式是什么? (我的意思是,确保在执行下一行代码时选择它,或者执行synchronously。)

PS。我知道我可以简单地为其Text属性分配文本,但这不是我要求的。您可以在我的ComboBox实现中看到,我可以为每个项目分配自定义对象,而且我依赖于许多基于选择的事件,例如SelectedIndexChanged

PS2。我不确定这是否仅影响具有DropDown样式的组合框或所有组合框。

3 个答案:

答案 0 :(得分:1)

嗯,当您将对象作为SelectedValue的来源时,可以使用SelectedItemComboBox执行此操作。

看一下这篇文章:Understanding SelectedValue, SelectedValuePath, SelectedItem & DisplayMemberPath。你有代码示例也可以运行。

来自文章:

SelectedItem :这将返回列表/组合框/容器中当前选定的项目。你可以看到这是一个对象(因为我的列表包含对象)。如果List / Combobox / etc包含字符串列表,则它将是一个字符串。如果它包含整数,它将是一个int。

SelectedValuePath :设置此项将使属性SelectedValue返回您在此处选择的属性的值。在我们的示例中,选择“ShapeColor”将使SelectedValue仅返回颜色,而不是整个形状对象。

SelectedValue :如果您只想要一个对象的一部分,请设置上面的属性,并在此处获取该属性的值。请注意,如果未使用SelectedValuePath,则与使用SelectedItem相同。

DisplayMemberPath :将此设置为对象的属性,将导致GUI在选择类时显示该属性,而不是查看类名或类ToString()方法(应该总是提供。看看本书的ToC中的第5项。

免责声明:我是文章的作者......

答案 1 :(得分:1)

我敢打赌,在您打开MessageBox之前,没有处理更改选择时触发的事件。

尝试添加此内容:

Application.DoEvents();

...在致电MessageBox.Show();之前,看看是否有帮助。如果是,您可以尝试通过

使控件重新同步重绘
comboBox.Refresh();

如果您正在线程,可以尝试comboBox.Invoke。此外,PerformLayout / Form上的Control有时会迫使这些事情发生,而不是等待绘制消息。

MessageBox.Show停止其轨道中的所有表单处理。当您确定组合框已经完成了它需要做的所有事情时,最终的解决方案可能是将它放在不同的地方。

答案 2 :(得分:1)

您的消息框会中断ComboBox处理以更新所选索引。此行为是间歇性的,因为表单和控件(如ComboBox和消息框)依赖于Windows邮件系统。表单的其他部分可能会在您的选择更改和消息框的同时生成数百条消息(有时更多,有时更少)。当有大量消息时,系统可能无法处理某些消息,因此所选索引不会更改。

避免此问题的两个选项:

  • 在对显示消息框的新索引SelectedIndex进行完整性检查后设置i
  • 使用BeginInvoke(例如下面的例子)异步检查你的健全性,即。 之后,系统已完成对已更改的选定索引的消息处理。

使用BeginInvoke:

的一种方法
comboBox.SelectedIndex = i;

// Sanity check new index i after message processing for the combo box.
comboBox.BeginInvoke(delegate()
{
    if (/* sanity check fails */)
    {
        MessageBox("Error");
    }   
});

修改:正如另一个答案所示,您可能会使用Application.DoEvents获得所需的行为,但我会steer clear of这种做法。