2014-10-28 45 views
5

通过绑定同步两组数据的最佳方式是什么?现在双向收集绑定同步/锁

Target = Custom Setters - raises custom events whenever something changed 
Source = ObservableCollection - raises events whenever collection changed 

我的问题是,当我收到从一个集合(例如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; 
} 

我看到您可以使用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; 
} 

后谷歌+ SO搜索无功而返,我想看看别人是如何做,并且有很简单的东西,我在这里失踪,解决这个问题呢? (我知道这些例子不是线程安全的)

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

我问的原因是因为,目前我正在实施附加行为,并为每个行为,我创建2套字典其中每个对象的处理程序都有引用,因为状态必须传递。

我似乎无法找到.NET Binding类的绑定机制的源代码,看看MS如何实现它。如果任何人有一个链接到那些将不胜感激。

+0

对不起,我可能会丢失一些东西,但是为什么您的设计要求您忽略每次发生更改时发生的一些事件?我无法弄清楚你想完成什么。你能否说出你想解决的问题? – furkle 2014-10-28 23:51:02

+0

因为如果您订阅双方,您将收到双方的通知。造成无限循环。例如。Customibject引发事件发生变化,我的处理程序被调用并更改绑定的集合,这反过来引发了更改的事件,所以我的集合更改了处理程序被调用,其中编辑了自定义对象。这会再次引发事件,并且你处于循环中 – 2014-10-29 00:22:36

+2

对,我说的是设计你的程序的方式必须有意地阻止它进入无限循环,这是一个相当大的代码味道。是否有理由不只是通过INotifyPropertyChanged处理对集合的更改,还是我误解了你的目的? – furkle 2014-10-29 00:24:58

回答

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); 
     } 
    } 
} 

然后你可以写:

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

这不一定是任何短 - 它可能是更长的时间来写,但如果发生异常,将确保您可以释放块。如果您经常使用它,您总是可以继承Guard以减少使用量。