ObservableCollection和线程

时间:2010-02-19 00:17:29

标签: c# wpf multithreading observablecollection

我班上有一个ObservableCollection。进一步进入我的课程,我有一个主题。从这个帖子我想添加到我的ObservableCollection。但我不能这样做:

  

这种类型的CollectionView不支持从与Dispatcher线程不同的线程更改其SourceCollection。

请注意,这不是从UI线程发生的,因此我无权访问调度程序。

3 个答案:

答案 0 :(得分:16)

JaredPar的方法是有效的。另一种值得考虑的方法是使用线程安全ObservableCollection而不是内置ObservableCollection。有一些实现,但我认为Sasha Barber's implementationCLinq 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