以线程安全的方式循环访问 CombBox.items

本文关键字:访问 CombBox items 循环 方式 线程 安全 | 更新日期: 2023-09-27 17:57:01

如何以线程安全的方式迭代C# WinForms ComboBox.Items 集合(有关示例,请参阅下面的代码)?对于集合,可以使用我控制锁定,但我不控制 comboBox.Items 集合,因为它由其数据绑定源更新(如果我想保持此方法可重用,我无法与此代码中的任何特定数据绑定源交互)。有一个 comboBox.Items.CopyTo 方法,但我需要先创建一个数组,并且计数可能会在创建数组和执行复制之间发生变化?

感谢您的任何建议。

private void SetComboBoxWidth(ComboBox comboBox, bool setDropDownWidth)
{
    int maxWidth = 0;
    using (Graphics graphics = comboBox.CreateGraphics())
    {
        foreach (object item in comboBox.Items)
        {
            int curWidth = TextRenderer.MeasureText(graphics, item.ToString(), comboBox.Font).Width;
            if (curWidth > maxWidth)
            {
                maxWidth = curWidth;
            }
        }
    }
    maxWidth += SystemInformation.VerticalScrollBarWidth;
    if (setDropDownWidth)
    {
        comboBox.DropDownWidth = maxWidth;
    }
    else
    {
        comboBox.Width = maxWidth;
    }
}

编辑:上面的代码抛出:{System.InvalidOperationException} 集合被修改;枚举操作可能无法执行。

组合框的设置包括:

myComboBox.ComboBox.DataSource = new BindingList<IMyInterface>(); 

调用链是:MyForm.OnLoad->MyForm.Setup->MyForm.SetComboBoxWidth

编辑 2:更改了示例代码,使其在循环期间根本不更改 ComboBox(以前的版本可能会在每次迭代时调整宽度)。

以线程安全的方式循环访问 CombBox.items

不应在多个线程中更新 UI。如果您遵循此规则,则无需担心线程安全性,因为它们仅由"主线程"更新。

如果需要在另一个线程中更新 UI,将使用 Control.InvokeControl.BeginInvoke 将控件传递给 UI 线程。

回答我自己的问题,以防其他人遇到这个问题,尽管我对发生的事情没有完全了解。

存储在 BindingList 中的 IMyInterface 对象也实现了 INotifyPropertyChanged。后台线程可以更改 IMyInterface 对象中的属性,从而导致发生 INotifyPropertyChanged.PropertyChanged。当 BindingList 数据源中对象的属性发生更改时,ComboBox 会重新创建其列表(我认为无论如何都会发生这种情况,不确定)。如果在 foreach 迭代时发生这种情况,则会抛出 InvalidOperationException。

我通过创建 BindingList 的一个子类来解决此问题,该子类在必要时覆盖 OnListChanged 以调用。这似乎已经解决了问题。

感谢回答和评论并指出正确方向的人。