C# 可观察收集和线程

C# 可观察收集和线程,c#,wpf,multithreading,observablecollection,C#,Wpf,Multithreading,Observablecollection,我班上有一个可观察到的集合。在我的课堂上,我有一条线索。我想从这个线程添加到我的observateCollection。但我不能这么做: 此类型的CollectionView不支持从不同于Dispatcher线程的线程更改其SourceCollection 请注意,这不是从UI线程发生的,因此我没有访问dispatcher的权限。解决此问题的最佳方法是将dispatcher对象传递给后台线程的start方法 void DoBackgroundOperation(ObservableCollect

我班上有一个
可观察到的集合
。在我的课堂上,我有一条线索。我想从这个线程添加到我的
observateCollection
。但我不能这么做:

此类型的CollectionView不支持从不同于Dispatcher线程的线程更改其SourceCollection


请注意,这不是从UI线程发生的,因此我没有访问dispatcher的权限。

解决此问题的最佳方法是将
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);
}

JaredPar的方法是有效的。另一种值得考虑的方法是使用线程安全的
observateCollection
,而不是内置的
observateCollection
。有一些实现,但在我看来,它们是一些更好的实现。在内部,这些类基本上使用JaredPar概述的方法,但将其封装在collection类中。

在.Net 4.5中,您可以使用线程安全集合、ConcurrentDictionary、ConcurrentBag等,以满足您的需要:


也请考虑阅读:

+ 1:同样的方法可以使用SimultIsActudio上下文。当前,而不是调度器,如果您不想接受WPF依赖关系(即:您也希望在Windows窗体中使用此代码)。添加了一个带有
SynchronizationContext
的解决方案,该解决方案具有功能性。感谢您的回答。我将在明天凌晨1:30在这里看这篇文章。@JaredPar:如果一个集合将用于仅视图WPF控件,并且它的备份存储对多个读卡器是线程安全的,那么让UI线程进程单独更新与让集合引发IObservableCollection“重置”相比,有哪些优点和缺点如果集合自上次引发此类事件后已被修改,是否在UI线程上发生?据我所知,“收藏重置”事件应该会导致收藏的任何消费者认为所有物品都可能已更改,并采取相应的行动。就我个人而言,我无法使其与提供的链接一起工作。我需要使用您提到的JaredPas方法。请尝试以下链接,该链接提供了一个线程安全解决方案,可从任何线程运行,并可通过多个UI线程绑定到该解决方案:AnthonyPaulO引用的文章需要Immutable Collections NuGet包,并且仅适用于.NET4.5。NET4.0有类似的版本吗?这是我目前发现的最好的版本,它可以同步外部事件处理。但是,您必须传递GUI线程的SynchronizationContext(即Dispatcher),当我单击它们时,这两个链接似乎都是垃圾邮件。
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);
}