2014-10-28 4 views
5

Каков наилучший способ синхронизации двух наборов данных посредством привязки?TwoWay Collection Binding Sync/Lock

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

Я видел, что вы можете использовать, если заявление, чтобы проверить наличие обновлений от источника, и если они игнорируют их. например

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

После Google + SO Поиск вернулся ни с чем, я хотел бы видеть, как другие люди делают это, и есть что-то действительно просто я здесь отсутствует, что решает эту проблему? (Я знаю, что примеры не являются потокобезопасными)

Если нет, то каким образом? Удаление и установка обработчиков или установка булевского флага? Что более результативно (да, я знаю, что это маловероятно, чтобы вызвать узкое место, но из любопытства)

Причина, о которой я прошу, заключается в том, что в настоящее время я реализую Attached Behaviors и для каждого поведения создаю 2 набора словарей которые содержат ссылки на обработчики для каждого объекта, поскольку состояние должно быть передано.

Я не могу найти исходный код для механизма привязки классов привязки .NET, чтобы увидеть, как MS его реализовала. Если у кого есть ссылка на те, это было бы весьма признательно.

+0

Извините, мне что-то не хватает, но почему ваш дизайн требует от вас игнорировать некоторые из событий, которые вы стреляете каждый раз, когда что-то меняется? Я не могу понять, что вы пытаетесь выполнить. Можете ли вы сказать, в чем проблема, которую вы пытаетесь решить? – furkle

+0

Потому что, если вы подписаны на обе стороны, вы получите уведомления с обеих сторон. Вызов бесконечного цикла. Например.Customibject вызывает событие, которое оно изменило, мой обработчик вызван и изменяет связанную коллекцию, которая, в свою очередь, вызывает измененные события, поэтому меняет вызов обработчика, который редактирует пользовательский объект. Это снова приводит к событиям, и вы находитесь в цикле –

+2

Правильно, я говорю, что разработка вашей программы таким образом, что вы должны сознательно остановить ее от перехода в бесконечный цикл, - довольно большой запах кода. Есть ли причина, по которой вы не просто обрабатываете изменения в своих коллекциях через INotifyPropertyChanged, или я не понимаю вашу цель? – furkle

ответ

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, чтобы уменьшить использование, если вы будете использовать его часто.