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如何实现它.如果有人有这些链接,将不胜感激.
您正在使用的机制 - 使用一个布尔值来跟踪更新何时发生,并围绕它进行阻止,是最常见的方法。
就我个人而言,我更喜欢将该逻辑包装到一个实现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如果您经常使用它,您始终可以进行子类化以减少使用量。