我班上有一个ObservableCollection
。进一步进入我的课程,我有一个主题。从这个帖子我想添加到我的ObservableCollection
。但我不能这样做:
这种类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection。
请注意,这不是从UI线程发生的,因此我无权访问调度程序。
答案 0 :(得分:16)
JaredPar的方法是有效的。另一种值得考虑的方法是使用线程安全ObservableCollection
而不是内置ObservableCollection
。有一些实现,但我认为Sasha Barber's implementation和CLinq Continuous Collection class是一些更好的实现。在内部,这些类基本上使用JaredPar概述的方法,但将其封装在集合类中。
答案 1 :(得分:14)
解决此问题的最佳方法是将Dispatcher
对象传递给后台线程的start方法。
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);
}
答案 2 :(得分:6)
在In.Net 4.5中,您可以使用Thread-safe集合,ConcurrentDictionary,ConcurrentBag等,以满足您的需求:http://msdn.microsoft.com/en-us/library/dd997305.aspx
请考虑阅读:http://www.codeproject.com/Articles/208361/Concurrent-Observable-Collection-Dictionary-and-So