ObservableCollection和线程

Eri*_*kTJ 29 c# wpf multithreading observablecollection

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

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

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

Jar*_*Par 15

解决此问题的最佳方法是将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);
}
Run Code Online (Sandbox Code Playgroud)

现在,稍后当您需要添加到集合时,您可以使用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);
}
Run Code Online (Sandbox Code Playgroud)

  • +1:此外,如果您不想采用WPF依赖关系(即:您还希望在Windows窗体中使用此代码),则可以使用SynchronizationContext.Current而不是调度程序来完成相同的方法. (3认同)

Szy*_*zga 15

JaredPar的方法是有效的.另一种值得考虑的方法是使用线程安全ObservableCollection而不是内置ObservableCollection.那里有一些实现,但在我看来,Sasha Barber的实现CLinq Continuous Collection类是一些更好的实现.在内部,这些类基本上使用JaredPar概述的方法,但将其封装在集合类中.


Cor*_*ian 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