У меня есть приложение Windows Forms, которое отображает форму с DataGridView, привязанной к пользовательской коллекции, которая наследует BindingList. Я использую механизм BindingSource / DataSource для привязки данных. Форма представляет собой монитор, который отображает информацию о состоянии, содержащуюся в коллекции. Каждый элемент коллекции представляет информацию о состоянии одного из множества дочерних потоков.
Я использую подход SynchronizationContext, чтобы удостовериться, что событие ListChanged из моей коллекции синхронизировано с потоком пользовательского интерфейса и не возникает проблем с многопоточностью. Тем не менее, кажется, что несколько потоков могут работать с коллекцией одновременно. Это вызывает проблемы с привязкой данных. Ниже приведен пример произошедшего исключения:
> 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 было инициировано и обработано потоком пользовательского интерфейса.
Итак, мой вопрос состоит в том, как сделать мою коллекцию не только поточно-ориентированной, но и блокирующей, чтобы пользовательский интерфейс мог обновляться после события ListChanged, прежде чем разрешено другое изменение? Недостаточно ставить в очередь события ListChanged, мне нужно заблокировать операцию, которая привела к запуску события ListChanged. Например, если я изменил свойство элемента, а затем вызвал событие ListChanged (ListChangedType = ItemChanged), другой поток, который пытается добавить элемент в коллекцию, блокируется до тех пор, пока не вернутся обработчики событий ListChanged.
Есть идеи?