BindingOperations.EnableCollectionSynchronization 和 CollectionChanged 在多线程 WPF 应用程序中的交互

Interaction of BindingOperations.EnableCollectionSynchronization and CollectionChanged in multi threaded WPF application

我正在尝试开发多线程 WPF 应用程序。作为其中的一部分,我正在使用...

BindingOperations.EnableCollectionSynchronization(
                            IEnumerable collection,
                            object context,
                            CollectionSynchronizationCallback synchronizationCallback)

... 以避免工作线程更新 ListView 这将导致异常。

ObservableCollection 在工作线程上引发 CollectionChanged 时,以上将确保转换到 UI 线程。

您可以在 synchronizationCallback 中实现自己的锁,如下所示:

protected void synchronizationCallback(
            IEnumerable collection,
            object context,
            Action accessMethod,
            bool writeAccess)
{
    ReaderWriterLockSlim listLock = context as ReaderWriterLockSlim;

    if (writeAccess)
    {
        listLock.EnterWriteLock();

        accessMethod();

        listLock.ExitWriteLock();                

        return;
    }

    listLock.EnterReadLock();

    accessMethod();

    listLock.ExitReadLock();
}

但是为了避免递归锁,我发现我需要在引发 CollectionChanged.

之前退出 ObservableCollection
protected override void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
{
    Debug.Assert(!this.listLock.IsReadLockHeld);
    Debug.Assert(this.listLock.IsWriteLockHeld);

    this.listLock.ExitWriteLock();

    base.OnCollectionChanged(e);

    this.listLock.EnterWriteLock();
}

因此,在synchronizationCallback中遇到锁之前,另一个工作线程可能会进入ObservableCollection。因此,.NET Framework 代码如果需要读取 ObservableCollection,最终可能会读取与 NotifyCollectionChangedEventArgs.

中通知的状态不同的状态

但是,这是个问题吗?我的想法是不,因为 ListView 只会更新为以后的状态。

是的,这是一个问题 - 您可能会收到“在 OnCollectionChanged 事件期间无法更改集合”异常,因为在第二个工作线程尝试之前事件可能尚未完成改变集合的状态。