以线程安全的方式循环访问 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(以前的版本可能会在每次迭代时调整宽度)。
不应在多个线程中更新 UI。如果您遵循此规则,则无需担心线程安全性,因为它们仅由"主线程"更新。
如果需要在另一个线程中更新 UI,将使用 Control.Invoke
或 Control.BeginInvoke
将控件传递给 UI 线程。
回答我自己的问题,以防其他人遇到这个问题,尽管我对发生的事情没有完全了解。
存储在 BindingList 中的 IMyInterface 对象也实现了 INotifyPropertyChanged。后台线程可以更改 IMyInterface 对象中的属性,从而导致发生 INotifyPropertyChanged.PropertyChanged。当 BindingList 数据源中对象的属性发生更改时,ComboBox 会重新创建其列表(我认为无论如何都会发生这种情况,不确定)。如果在 foreach 迭代时发生这种情况,则会抛出 InvalidOperationException。
我通过创建 BindingList 的一个子类来解决此问题,该子类在必要时覆盖 OnListChanged 以调用。这似乎已经解决了问题。
感谢回答和评论并指出正确方向的人。