TwoWay Collection绑定同步/锁定

Mic*_*han 5 .net c# wpf binding synchronization

通过Binding同步两组数据的最佳方法是什么?

Target = Custom Setters - raises custom events whenever something changed
Source = ObservableCollection - raises events whenever collection changed
Run Code Online (Sandbox Code Playgroud)

现在我的问题是,当我从一个集合(例如Source.CollectionChanged事件)收到更新时,我需要调用自定义TargetSetters,并忽略源自我的更新的调用事件.

另一方面,当Target自定义事件被触发时,我需要更新源,但忽略CollectionChanged事件.

目前,我正在保留对我的处理程序的引用,并在更新任何集合之前删除它.例如

private void ObservableCollection_OnCollectionChanged(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
{
    CustomObject.SelectionChanged -= CustomObject_SelectionChanged;
    // Do change logic and update Custom Object....
    CustomObject.SelectionChanged += CustomObject_SelectionChanged;
}

void CustomObject_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
    ObservableCollection.CollectionChanged -= ObservableCollection_OnCollectionChanged;
    // Do change logic and update ObservableCollection...
    ObservableCollection.CollectionChanged += ObservableCollection_OnCollectionChanged;
}
Run Code Online (Sandbox Code Playgroud)

我已经看到你可以使用if语句来检查更新是否来自源,以及它们是否忽略它们.例如

private void ObservableCollection_OnCollectionChanged2(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
{
    if (BindingTargetUpdating) return;
    BindingSourceUpdating = true;
    // Do change logic and update Custom Object....
    BindingSourceUpdating = false;
}

void CustomObject_SelectionChanged2(object sender, SelectionChangedEventArgs e)
{
    if (BindingSourceUpdating) return;
    BindingTargetUpdating = true;
    // Do change logic and update ObservableCollection...
    BindingTargetUpdating = false;
}
Run Code Online (Sandbox Code Playgroud)

在谷歌+ SO搜索没有任何回复后,我想看看其他人是如何做到这一点的,有什么非常简单的我在这里找不到解决这个问题的东西?(我知道这些例子不是线程安全的)

如果没有,首选方式是什么?删除和附加处理程序,或设置布尔标志?什么是更高性能(是的,我知道这不太可能导致瓶颈,但出于好奇)

我要问的原因是因为,目前我正在实现附加行为,并且对于每个行为,我创建了两组字典,其中包含对每个对象的处理程序的引用,因为状态必须被传递.

我似乎无法找到.NET Binding类的绑定机制的源代码,以了解MS如何实现它.如果有人有这些链接,将不胜感激.

Ree*_*sey 3

您正在使用的机制 - 使用一个布尔值来跟踪更新何时发生,并围绕它进行阻止,是最常见的方法。

就我个人而言,我更喜欢将该逻辑包装到一个实现IDisposable. 这样可以更轻松地保证您总是会自己清理干净。

您可以使用的实用程序如下所示:

class Guard : IDisposable
{
    readonly Func<bool> getter;
    readonly Action<bool> setter;

    readonly bool acquired = false;
    public Guard(Func<bool> getter, Action<bool> setter)
    {
        this.getter = getter;
        this.setter = setter;

        if (this.getter() == false)
        {
            this.setter(true);
            this.acquired = true;
        }
    }

    public bool Acquired { get { return this.acquired; } }

    void IDisposable.Dispose()
    {
        if (acquired)
        {
            this.setter(false);
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

然后你可以写:

private void ObservableCollection_OnCollectionChanged2(object sender, NotifyCollectionChangedEventArgs notifyCollectionChangedEventArgs)
{
    using(var guard = new Guard(() => BindingTargetUpdating, v => BindingTargetUpdating = value))
    {
       if (guard.Acquired)
       {
           // Do change logic and update Custom Object....
       }
    }
}
Run Code Online (Sandbox Code Playgroud)

这不一定更短 - 它可能写起来更长,但确实提供了在发生异常时释放块的保证。Guard如果您经常使用它,您始终可以进行子类化以减少使用量。