2014-10-28 13 views
5

Jaki jest najlepszy sposób synchronizacji 2 zestawów danych poprzez bindowanie?Synchronizacja z TwoWay Collection Binding Sync/Lock

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

Teraz moje pytanie brzmi, kiedy otrzyma aktualizację z jednej kolekcji (na przykład imprezy Source.CollectionChanged) Muszę zadzwonić do niestandardowych TargetSetters i ignorować wydarzenia zwane który pochodzi z mojego aktualizacji.

A także w inny sposób, gdy uruchamiane są zdarzenia niestandardowe Target, muszę zaktualizować źródło, ale zignorować zdarzenie CollectionChanged.

W tej chwili zachowuję odniesienie do moich programów obsługi i usuwam je przed aktualizacją którejkolwiek z kolekcji. na przykład

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

Widziałem, że można użyć instrukcji if, aby sprawdzić, czy aktualizacje pochodzą ze źródła i czy są one ignorowane. na przykład

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

Po Google + SO Szukaj wrócili z niczym, chciałem zobaczyć, jak inni ludzie robią to, i to jest coś naprawdę proste, brakuje mi tutaj, że rozwiązuje ten problem? (Wiem, że przykłady nie są bezpieczne dla wątków)

Jeśli nie, jaki jest preferowany sposób? Usuwanie i dołączanie procedur obsługi lub ustawianie flagi boolowskiej? Co jest bardziej wydajne (tak, wiem, że jest to mało prawdopodobne, aby spowodować wąskie gardło, ale z ciekawości)

Powód, o który pytam, ponieważ obecnie wdrażam Attached Behaviors i dla każdego zachowania, tworzę 2 zestawy słowników które przechowują odniesienia do modułów obsługi dla każdego obiektu, ponieważ stan musi być przekazywany.

Nie mogę znaleźć kodu źródłowego mechanizmu powiązania klas wiązania .NET, aby zobaczyć, w jaki sposób MS zaimplementowało go. Jeśli ktokolwiek ma link do nich, byłoby to bardzo cenne.

+0

Przepraszam, może brakuje mi czegoś, ale dlaczego twój projekt wymaga ignorowania niektórych wydarzeń, które strzelasz za każdym razem, gdy coś się zmieni? Naprawdę nie mogę zrozumieć, co próbujesz osiągnąć. Czy możesz podać, na czym polega problem, który próbujesz rozwiązać? – furkle

+0

Bo jeśli zasubskrybujesz obie strony, będziesz otrzymywać powiadomienia z obu stron. Powodować nieskończoną pętlę. Na przykład.Customibject podnosi wydarzenie, które się zmieniło, mój program obsługi zostanie wywołany i zmieni powiązaną kolekcję, która z kolei podnosi zmienione zdarzenia, więc moja kolekcja zmieniła nazwę wywoływacza, który edytuje niestandardowy obiekt. To znowu podnosi wydarzenia i jesteś w pętli –

+2

Dobrze, mówię, że projektowanie twojego programu w taki sposób, że musisz celowo powstrzymać go od wejścia w nieskończoną pętlę to dość duży zapach kodu. Czy istnieje powód, dla którego nie zajmujesz się tylko zmianami w twoich kolekcjach poprzez INotifyPropertyChanged, czy też nie rozumiem twojego celu? – furkle

Odpowiedz

3

Mechanizm, którego używasz - mający wartość boolowską, która śledzi, kiedy występują aktualizacje i blokuje wokół niej, jest najbardziej powszechnym podejściem.

Osobiście wolę zawrzeć tę logikę w małym narzędziu, które implementuje IDisposable. Ułatwia to zagwarantowanie, że zawsze będziesz sprzątał po sobie.

Narzędzie można użyć do tego będzie wyglądać następująco:

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

Następnie można napisać:

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

To niekoniecznie jest krótszy - jego prawdopodobnie już pisać, ale zapewnia gwarancje, że zwolnisz swoje bloki, jeśli wystąpią wyjątki. Zawsze możesz podklasę Guard zmniejszyć użycie, jeśli będziesz go często używać.