Подтвердить что ты не робот

ObservableCollection и резьба

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

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

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

4b9b3361

Ответ 1

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

Ответ 2

Лучший способ решить это - передать объект 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);
}