ObservableCollection и поточная обработка

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

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

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

29
задан Dave Clemmer 26 September 2011 в 17:25
поделиться

2 ответа

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

15
ответ дан 28 November 2019 в 01:55
поделиться

Лучший способ решить эту проблему - передать объект 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);
}
15
ответ дан 28 November 2019 в 01:55
поделиться
Другие вопросы по тегам:

Похожие вопросы: