Я имею ObservableCollection
в моем классе. И далее в мой класс у меня есть поток. От этого потока я хотел бы добавить к моему ObservableCollection
. Но я не могу сделать этого:
Этот тип CollectionView не поддерживает изменения в своем SourceCollection от потока, отличающегося от потока Диспетчера.
Обратите внимание, что этого не происходит от потока UI, таким образом, у меня нет доступа к диспетчеру.
Подход JaredPar является правильным. Другой подход, который стоит рассмотреть, это использование потокобезопасной ObservableCollection
вместо встроенной ObservableCollection
. Существует несколько реализаций, но реализация Саши Барбера и класс CLinq Continuous Collection, на мой взгляд, являются одними из лучших. Внутри эти классы, по сути, используют подход, описанный JaredPar, но инкапсулируют его внутри класса коллекции.
Лучший способ решить эту проблему - передать объект 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);
}