2014-04-07 19 views
0

如何以線程安全的方式遍歷C#WinForms ComboBox.Items集合(請參閱下面的示例代碼)?使用集合我可以使用控制鎖定,但我不控制comboBox.Items集合,因爲它通過其數據綁定源進行更新(如果我想保持此方法可重用,則無法與任何特定的數據綁定源進行交互在這個代碼中)。有一個comboBox.Items.CopyTo方法,但我需要先創建一個數組,計數可能會在創建數組和執行復制之間改變?以線程安全的方式對CombBox.Items進行迭代

感謝您的任何建議。

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(以前的版本可能會調整每次迭代的寬度)。

+0

WinForms是單線程的。如果你不直接在另一個線程中做任何事情,它總是線程安全的。這意味着,即使數據源更新是在另一個線程中進行的,更新也會在正確的UI線程中分派。當然,如果你改變foreach循環內comboBox.Items枚舉會失敗,但這是真實的任何列舉...... –

+0

@Adriano 上面的示例代碼拋出: 集合已修改;枚舉操作可能不會執行。 {System.InvalidOperationException} – FPike

+0

拋出什麼? - 編輯:打字太慢 – toATwork

回答

0

不應該在多個線程中更新UI。如果遵循此規則,則不必擔心線程安全問題,因爲它們僅由「主線程」更新。

如果完全需要在另一個線程中更新UI,則可以使用Control.InvokeControl.BeginInvoke將控件傳遞給UI線程。

0

回答我自己的問題,以防其他人遇到這個問題,但我沒有完全理解發生了什麼。

存儲在BindingList中的IMyInterface對象也實現INotifyPropertyChanged。後臺線程可以更改IMyInterface對象中的屬性,從而導致INotifyPropertyChanged.PropertyChanged發生。當BindingList DataSource中的對象的屬性發生更改時,ComboBox將重新創建它的列表(我認爲這是發生的事情,無論如何,不​​確定)。如果foreach迭代時發生這種情況,則會引發InvalidOperationException。

我工作圍繞這一問題,通過創建的BindingList的子類,覆蓋OnListChanged在必要時調用。這似乎解決了這個問題。

感謝回答並評論並指出正確方向的人。