Реализуйте потокобезопасный сбор для привязки данных в .NET - PullRequest
2 голосов
/ 27 мая 2009

У меня есть приложение Windows Forms, которое отображает форму с DataGridView, привязанной к пользовательской коллекции, которая наследует BindingList. Я использую механизм BindingSource / DataSource для привязки данных. Форма представляет собой монитор, который отображает информацию о состоянии, содержащуюся в коллекции. Каждый элемент коллекции представляет информацию о состоянии одного из множества дочерних потоков.

Я использую подход SynchronizationContext, чтобы удостовериться, что событие ListChanged из моей коллекции синхронизировано с потоком пользовательского интерфейса и не возникает проблем с многопоточностью. Тем не менее, кажется, что несколько потоков могут работать с коллекцией одновременно. Это вызывает проблемы с привязкой данных. Ниже приведен пример произошедшего исключения:

System.ArgumentOutOfRangeException: Указанный аргумент был вне диапазон допустимых значений. Имя параметра: rowIndex в System.Windows.Forms.DataGridView.GetCellDisplayRectangle (Int32 columnIndex, Int32 rowIndex, Boolean cutOverflow) в System.Windows.Forms.DataGridView.GetCellAdjustedDisplayRectangle (Int32 columnIndex, Int32 rowIndex, Boolean cutOverflow) в System.Windows.Forms.DataGridView.InvalidateCellPrivate (Int32 columnIndex, Int32 rowIndex) в System.Windows.Forms.DataGridView.OnCellCommonChange (Int32 columnIndex, Int32 rowIndex) в System.Windows.Forms.DataGridView.DataGridViewDataConnection.ProcessListChanged (ListChangedEventArgs есть System.Windows.Forms.DataGridView.DataGridViewDataConnection.currencyManager_ListChanged (Объект отправитель, ListChangedEventArgs e) в System.Windows.Forms.CurrencyManager.OnListChanged (ListChangedEventArgs есть System.Windows.Forms.CurrencyManager.List_ListChanged (Объект отправитель, ListChangedEventArgs e) в System.Windows.Forms.BindingSource.OnListChanged (ListChangedEventArgs есть System.Windows.Forms.BindingSource.InnerList_ListChanged (Объект отправитель, ListChangedEventArgs e)

Это заставляет меня поверить, что коллекция была снова изменена после того, как начальное событие ListChanged было инициировано и обработано потоком пользовательского интерфейса.

Итак, мой вопрос заключается в том, как сделать мою коллекцию не только поточно-ориентированной, но и блокирующей, чтобы пользовательский интерфейс мог обновляться после события ListChanged, прежде чем разрешено другое изменение? Недостаточно ставить в очередь события ListChanged, мне нужно заблокировать операцию, которая привела к запуску события ListChanged. Например, если я изменил свойство элемента, а затем вызвал событие ListChanged (ListChangedType = ItemChanged), другой поток, который пытается добавить элемент в коллекцию, блокируется до тех пор, пока не вернутся обработчики событий ListChanged.

Есть идеи?

Ответы [ 2 ]

0 голосов
/ 20 сентября 2010

Попробуйте ConcurrentBag<T>

0 голосов
/ 27 мая 2009

Свяжите представление с копией коллекции, затем соответствующим образом управляйте доступом к коллекции: убедитесь, что потоки выполняют свои обновления в секции lock (), и убедитесь, что копирование также выполняется с использованием lock () для того же объекта ,

Это также позволит вам ставить запросы на запись в очередь, чтобы авторы не блокировали, а просто отправляли сообщение со своим обновлением, что может быть полезно по соображениям производительности.

Просто идея.

...