ObservableCollection и threading - PullRequest
       7

ObservableCollection и threading

28 голосов
/ 19 февраля 2010

У меня есть ObservableCollection в моем классе. А дальше в мой класс у меня есть нить. Из этой ветки я бы хотел добавить в мой ObservableCollection. Но я не могу этого сделать:

Этот тип CollectionView не поддерживает изменения в его SourceCollection из потока, отличного от потока Dispatcher.

Обратите внимание, что этого не происходит в потоке пользовательского интерфейса, поэтому у меня нет доступа к диспетчеру.

Ответы [ 3 ]

16 голосов
/ 19 февраля 2010

Подход JaredPar является верным. Другим подходом, который стоит рассмотреть, является использование многопоточного ObservableCollection вместо встроенного ObservableCollection. Существует несколько реализаций, но, на мой взгляд, реализация Саши Барбера и CLinq Continuous Collection class - одни из лучших. Внутренне эти классы по существу используют подход, изложенный JaredPar, но инкапсулируют его в классе коллекции.

14 голосов
/ 19 февраля 2010

Лучший способ решить эту проблему - передать объект Dispatcher методу запуска фонового потока.

void DoBackgroundOperation(ObservableCollection<SomeType> col) {
  var dispatcher = Dispatcher.CurrentDispatcher;
  ThreadStart start = () => BackgroundStart(dispatcher, col);
  var t = new Thread(start);
  t.Start();
}

private static void BackgroundStart(
    Dispatcher dispatcher, 
    ObservableCollection<SomeType> col) {
  ...
  SomeType t = GetSomeTypeObject();
  Action del = () => col.Add(t);
  dispatcher.Invoke(del);
}

Теперь позже, когда вам нужно добавить в коллекцию, вы можете использовать объект UI Dispatcher.

Как указал @Reed, более общее решение достигается с помощью SynchronizationContext. Вот пример функционального стиля с использованием SynchronizationContext для создания делегата, ответственного за добавление новых значений. Это имеет преимущество в том, что скрывает как коллекцию, так и модель потоков от кода, создающего объект.

void DoBackgroundOperation(ObservableCollection<SomeType> col) {
  var context = SynchronizationContext.Current;
  Action<SomeType> addFunc = (SomeType st) => context.Send(() => col.Add(st), null);
  ThreadStart start = () => BackgroundStart(addFunc);
  var t = new Thread(start);
  t.Start();
}

private static void BackgroundStart(Action<SomeType> addFunc) {
  ...
  SomeType t = GetSomeTypeObject();
  addFunc(t);
}
6 голосов
/ 20 октября 2013

В .Net 4.5 вы можете использовать потоки-безопасные коллекции, ConcurrentDictionary, ConcurrentBag и т. Д., В зависимости от того, что вам нужно:

Пожалуйста, прочитайте также: http://www.codeproject.com/Articles/208361/Concurrent-Observable-Collection-Dictionary-and-So

...