如何以线程安全的方式迭代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} Collection被修改;枚举操作可能无法执行。
组合框设置为:
myComboBox.ComboBox.DataSource = new BindingList<IMyInterface>();
调用链是:MyForm.OnLoad-&gt; MyForm.Setup-&gt; MyForm.SetComboBoxWidth
编辑2: 更改示例代码以在循环期间根本不更改ComboBox(之前的版本可能会在每次迭代时调整宽度)。
答案 0 :(得分:0)
您不应该更新多个线程中的UI。如果您遵循此规则,则不必担心线程安全,因为它们仅由&#34;主线程&#34;更新。
如果你需要在另一个线程中更新UI,你可以使用Control.Invoke
或Control.BeginInvoke
将控件传递给UI线程。
答案 1 :(得分:0)
回答我自己的问题以防其他人遇到这个问题,虽然我没有完全了解发生的事情。
存储在BindingList中的IMyInterface对象也实现了INotifyPropertyChanged。后台线程可以更改IMyInterface对象中的属性,从而导致发生INotifyPropertyChanged.PropertyChanged。当BindingList DataSource中对象的属性发生变化时,ComboBox会重新创建其列表(我想想无论如何都会发生这种情况,不确定)。如果在foreach迭代时发生这种情况,则抛出InvalidOperationException。
我通过创建BindingList的子类解决了这个问题,如果需要,它会将OnListChanged重写为Invoke。这似乎解决了这个问题。
感谢那些回答并评论并指出正确方向的人。