【问题标题】:Reliable selection of an item in a ComboBox with the DropDown style使用 DropDown 样式可靠地选择 ComboBox 中的项目
【发布时间】:2023-04-09 07:32:02
【问题描述】:

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

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

//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 样式的组合框,还是全部影响。

【问题讨论】:

    标签: c# .net winforms combobox


    【解决方案1】:

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

    尝试添加这个:

    Application.DoEvents();
    

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

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

    如果你正在线程,你可以试试comboBox.Invoke。此外,Form/Control 上的 PerformLayout 有时可以强制此类事情立即发生,而不是等待绘制消息。

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

    【讨论】:

    • 我最初确实尝试过Application.DoEvents();,但没有成功。我会改用Refresh();。谢谢。
    • 我认为Refresh 做到了。谢谢。
    【解决方案2】:

    好吧,当您将对象作为ComboBox 的源时,您可以使用SelectedValue 和SelectedItem 来做到这一点。

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

    来自文章:

    SelectedItem :这将返回 list/combobox/container 中当前选定的项目。如您所见,这是一个对象(因为我的列表包含对象)。如果您的 List/Combobox/etc 包含字符串列表,它将是一个字符串。如果它包含整数,它将是一个整数。

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

    SelectedValue :如果你只想要一个对象的一部分,设置上面的属性,你会在这里得到那个属性的值。请注意,如果不使用 SelectedValuePath,这与使用 SelectedItem 相同。

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

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

    【讨论】:

    • 我很感激。自从您写了一篇关于该控件的文章后,您是否目睹了我所描述的行为?
    • 我不喜欢依赖SelecetedIndex。如果您需要端口号,并假设它是您分配给ComboBox 的对象的属性,请在其上设置SelectedValuePath,然后使用SelectedValue,避免需要在索引处解析对象。话虽如此,我并没有遇到按我的方式进行选择的问题......
    【解决方案3】:

    您的消息框会中断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 这种方法。

    【讨论】:

    • 我想指出我是从同一个线程调用所有这些的。我还需要担心BeginInvoke吗?
    • 不确定您所说的担心是什么意思。您可以在同一 (UI) 线程上调用 BeginInvoke 以异步执行该代码,即。在控件完成其当前工作负载后(更改选定索引)。 BeginInvoke 不仅适用于非 UI 线程。
    猜你喜欢
    • 2018-06-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-10-30
    • 2015-01-21
    • 1970-01-01
    • 2014-07-02
    相关资源
    最近更新 更多