【发布时间】:2010-10-29 09:05:48
【问题描述】:
我有一个 Windows 窗体应用程序,它显示一个带有 DataGridView 的窗体,该窗体绑定到一个继承 BindingList 的自定义集合。我正在使用 BindingSource / DataSource 机制进行数据绑定。表单是一个监视器,显示集合中包含的状态信息。集合的每个元素代表多个子线程之一的状态信息。
我正在使用 SynchronizationContext 方法来确保我的集合中的 ListChanged 事件与 UI 线程同步,并且不会发生跨线程问题。但是,多个线程似乎仍然可以同时处理该集合。这会导致数据绑定问题。以下是已发生异常的示例:
> System.ArgumentOutOfRangeException: Specified argument was out of the range of valid values. Parameter name: rowIndex
> at System.Windows.Forms.DataGridView.GetCellDisplayRectangle(Int32 columnIndex, Int32 rowIndex, Boolean cutOverflow)
> at System.Windows.Forms.DataGridView.GetCellAdjustedDisplayRectangle(Int32 columnIndex, Int32 rowIndex, Boolean cutOverflow)
> at System.Windows.Forms.DataGridView.InvalidateCellPrivate(Int32 columnIndex, Int32 rowIndex)
> at System.Windows.Forms.DataGridView.OnCellCommonChange(Int32 columnIndex, Int32 rowIndex)
> at System.Windows.Forms.DataGridView.DataGridViewDataConnection.ProcessListChanged(ListChangedEventArgs e)
> at System.Windows.Forms.DataGridView.DataGridViewDataConnection.currencyManager_ListChanged(Object sender, ListChangedEventArgs e)
> at System.Windows.Forms.CurrencyManager.OnListChanged(ListChangedEventArgs e)
> at System.Windows.Forms.CurrencyManager.List_ListChanged(Object sender, ListChangedEventArgs e)
> at System.Windows.Forms.BindingSource.OnListChanged(ListChangedEventArgs e)
> at System.Windows.Forms.BindingSource.InnerList_ListChanged(Object sender, ListChangedEventArgs e)
这让我相信,在引发初始 ListChanged 事件并由 UI 线程处理后,集合再次更改。
所以,我的问题是如何使我的集合不仅是线程安全的,而且是阻塞的,以便 UI 可以在 ListChanged 事件之后刷新,然后再允许另一个更改?将 ListChanged 事件排队是不够的,我需要阻止导致 ListChanged 事件被触发的操作。例如,如果我更改元素的属性然后引发 ListChanged 事件 (ListChangedType = ItemChanged),则尝试将项目添加到集合中的另一个线程将被阻止,直到 ListChanged 事件处理程序返回。
有什么想法吗?
【问题讨论】:
标签: .net multithreading collections data-binding