ObservableCollection и резьба
У меня есть ObservableCollection
в моем классе. И далее в мой класс у меня есть нить. Из этой темы я хотел бы добавить к моему ObservableCollection
. Но я не могу этого сделать:
Этот тип CollectionView не поддерживает изменения в SourceCollection из потока, отличного от потока Dispatcher.
Обратите внимание, что это не происходит из потока пользовательского интерфейса, поэтому у меня нет доступа к диспетчеру.
Ответы
Ответ 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);
}
Ответ 3
In.Net 4.5 вы можете использовать коллекции, совместимые с потоками, ConcurrentDictionary, ConcurrentBag и т.д., в зависимости от ваших потребностей: http://msdn.microsoft.com/en-us/library/dd997305.aspx
Также рассмотрите возможность чтения: http://www.codeproject.com/Articles/208361/Concurrent-Observable-Collection-Dictionary-and-So