【问题标题】:Is WPF binding to concurrent collections safe?WPF 绑定到并发集合是否安全?
【发布时间】:2018-11-24 23:48:15
【问题描述】:

我想知道,将 WPF 控件绑定到并发集合是否安全,特别是围绕同样实现 INotifyCollectionChangedSystem.Collections.Concurrent 集合之一的包装类?

我知道CollectionChanged 必须在 UI 线程上调用(并且没有索引参数)。但是,如果另一个线程在 UI 更新自身时操作源集合,会发生什么情况? WPF 是否只是优雅地忽略了这个问题(就像在许多其他地方一样)?

【问题讨论】:

  • 绝对肯定,集合的枚举器必须是线程安全的,ConcurentBag 就是这种情况。幸运的是,wpf 带有 BindingOperations.EnableCollectionSynchronization,即使使用 ObservableCollection 或 List 也能解决这个问题。不可变集合也是一种选择

标签: wpf multithreading data-binding concurrent-collections


【解决方案1】:

这取决于你的包装器的实现。让我们做一个简单的例子,将INotifyCollectionChanged 添加到BlockingCollection<T> 以允许调用非 UI 线程:

public void AddNotified(T item)
{
    base.Add(item);

    var args = new NotifyCollectionChangedEventArgs(
        NotifyCollectionChangedAction.Add,
        item,
        Count - 1);

    //Ensure no items are changed until the UI is updated

    Application.Current.Dispatcher.Invoke(() =>
        CollectionChanged?.Invoke(this, args));
}

Add 的实现本身是线程安全的,但要确保 UI 显示当前项目,您需要确保在添加和更新之间没有其他项目发生更改(参见代码中的注释)。

WPF 根据 NotifyCollectionChangedAction 更新 UI,并更新在提升 INotifyCollectionChanged.CollectionChanged 时传递的项目。这意味着 UI 依赖于这些信息。结果:临时集合更新导致 UI 不同步,直到引发更新或调用 NotifyCollectionChangedAction.Reset 并且 UI 显示不同的项目,例如在源集合中。

将集合与 UI 同步是一个非常广泛且有趣的话题。已经有多种解决方案可能与您的特定问题相匹配。为您提供一些解决此类问题的可能方法,请查看以下链接:

【讨论】:

    猜你喜欢
    • 2021-07-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    • 2011-06-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多