C# 以线程安全的方式迭代CombBox.Items

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

如何以线程安全的方式迭代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>(); 
myComboBox.ComboBox.DataSource=new BindingList();
调用链是:MyForm.OnLoad->MyForm.Setup->MyForm.setComboxWidth

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

您不应该在多个线程中更新UI。如果遵循此规则,则不必担心线程安全,因为它们只由“主线程”更新


如果您需要在另一个线程中更新UI,您将使用
control.Invoke
control.BeginInvoke
将控件传递给UI线程,以防其他人遇到此问题,尽管我不完全了解发生了什么

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

我通过创建BindingList的子类来解决这个问题,该子类重写OnListChanged,以便在必要时调用。这似乎解决了问题


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

WinForms是单线程的。如果您不直接在另一个线程中执行任何操作,那么它总是线程安全的。这意味着,即使数据源更新是在另一个线程中进行的,更新也会在正确的UI线程中调度。当然,如果您更改comboBox.Items在foreach循环中,枚举将失败,但对于任何枚举都是如此…@Adriano上面的示例代码抛出:Collection已修改;枚举操作不能执行。{System.invalidoOperationException}抛出的是什么编辑:打字太慢所以问题是…你们的数据来源是什么?何时/如何调用SetComboBoxWidth()?combobox的设置为:myComboBox.combobox.DataSource=new BindingList();SetComboBoxWidth是从一系列方法中调用的,这些方法最终在我的主窗体上被重写的WndProc中启动。