【问题标题】:ObservableCollection and threadingObservableCollection 和线程
【发布时间】:2011-01-18 14:12:42
【问题描述】:

我班上有一个ObservableCollection。在我的课堂上,我有一个线程。从这个线程我想添加到我的ObservableCollection。但我不能这样做:

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

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

【问题讨论】:

    标签: c# wpf multithreading observablecollection


    【解决方案1】:

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

    【讨论】:

    • +1:此外,如果您不想使用 WPF 依赖项(即:您还想在Windows 窗体)。
    • @Reed,用SynchronizationContext 添加了一个功能性的解决方案。
    • 感谢您的回答。我明天会看这个,因为这里是上午 01:30。
    • @JaredPar:如果一个集合将用于仅查看的 WPF 控件,并且它的后备存储对于多个读者来说是线程安全的,那么让 UI 线程处理更新的优缺点是什么单独地,如果自上次引发此类事件以来已修改集合,则与让集合在 UI 线程上引发 IObservableCollection“重置”事件?据我了解,“集合重置”事件应该导致集合的任何消费者假设所有项目都可能已更改并采取相应措施。
    【解决方案2】:

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

    【讨论】:

    • 就我个人而言,我无法使用提供的链接使其工作。我需要使用你提到的 JaredPas'a 方法。
    • 试试下面的链接,它提供了一个线程安全的解决方案,可以在任何线程上工作,并且可以通过多个 UI 线程绑定到:codeproject.com/Articles/64936/…
    • AnthonyPaulO 引用的文章需要不可变集合 NuGet 包,并且仅适用于 .NET4.5。 .NET4.0 有类似的东西吗?
    • 这是迄今为止我发现的最好的一个,它可以同步外部事件处理。您仍然必须通过 GUI 线程的 SynchronizationContext(即 Dispatcher)github.com/CoryCharlton/CCSWE.Core/blob/master/src/Core/…
    • 当我点击这两个链接时,它们似乎都是垃圾邮件。
    【解决方案3】:

    在.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

    【讨论】:

      猜你喜欢
      • 2011-06-03
      • 2021-01-30
      • 1970-01-01
      • 1970-01-01
      • 2014-08-03
      • 1970-01-01
      • 1970-01-01
      • 2014-05-31
      • 1970-01-01
      相关资源
      最近更新 更多