I have a Windows Forms application that displays a form with a DataGridView bound to a custom collection that inherits BindingList. I'm using the BindingSource / DataSource mechanism for data-binding. The form is a monitor that displays status information contained in the collection. Each element of the collection represents status information for one of many child threads.
I am using the SynchronizationContext approach to make sure that the ListChanged event from my collection is synchronized with the UI thread and no cross-threading issues occur. However, it appears that it is still possible for multiple threads to work with the collection at the same time. This causes problems with data-binding. Below is an example of an exception that has occurred:
> 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)
This makes me believe that the collection was changed again after the initial ListChanged event was raised and being handled by the UI thread.
So, my question is how to make my collection not only thread-safe but blocking so that the UI can refresh after a ListChanged event before another change is allowed? It's not enough to queue the ListChanged events, I need to block the operation that led to the ListChanged event being fired. For example, if I change the property of an element then raised the ListChanged event (ListChangedType = ItemChanged), another thread that is trying to add an item to the collection is blocked until the ListChanged event handler(s) return.
Any ideas?