2014-10-28 2 views
5

Was ist der beste Weg, um 2 Datensätze über Binding zu synchronisieren?TwoWay-Sammlung Binding Sync/Lock

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

Nun meine Frage ist, wenn ich ein Update von einer Sammlung (z Source.CollectionChanged Ereignis) empfangen Ich brauche die benutzerdefinierten TargetSetters zu nennen, und ignorieren die Ereignisse genannt, die von meinem Update stammt.

Und auch die andere Möglichkeit, wenn die benutzerdefinierten Ziele Ereignisse ausgelöst werden, muss ich die Quelle aktualisieren, aber das CollectionChanged-Ereignis ignorieren.

Im Moment behalte ich einen Verweis auf meine Handler und entferne das, bevor ich die Sammlungen aktualisiere. z.B.

Ich habe gesehen, dass Sie eine if-Anweisung verwenden können, um zu überprüfen, ob die Updates von der Quelle stammen und ob sie ignoriert werden. z.B.

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

Nach Google + SO Suche kam mit nichts zurück, ich wollte, das sehen, wie andere Menschen tun, und es ist etwas wirklich einfach ich hier fehlt, das dieses Problem löst? (Ich weiß, dass die Beispiele nicht threadsicher sind)

Wenn nicht, was ist der bevorzugte Weg? Handler entfernen oder hinzufügen oder eine boolesche Flagge setzen? Was ist performanter (ja ich weiß, das ist sehr unwahrscheinlich, einen Engpass aber aus Neugier)

Grund Ich frage ist, weil ich derzeit Attached Behaviors implementieren und für jedes Verhalten, ich bin 2 Sätze von Wörterbücher erstellen welche die Verweise auf die Handler für jedes Objekt als Zustand halten müssen.

Ich kann nicht den Quellcode für den Bindungsmechanismus der .NET Binding-Klassen finden, um zu sehen, wie MS es implementiert. Wenn jemand eine Verbindung zu diesen hat, würde es sehr geschätzt werden.

+0

Es tut mir leid, ich vermisse etwas, aber warum erfordert Ihr Design, dass Sie einige der Ereignisse ignorieren, die Sie jedes Mal auslösen, wenn sich etwas ändert? Ich kann nicht wirklich herausfinden, was du erreichen willst. Kannst du vielleicht sagen, was das Problem ist, das du lösen willst? – furkle

+0

Wenn Sie beide Seiten abonnieren, erhalten Sie Benachrichtigungen von beiden Seiten. Eine Endlosschleife verursachen. Z.B.Customibject löst ein Ereignis aus, das geändert wurde, mein Handler wird aufgerufen und ändert die gebundene Auflistung, was wiederum die geänderten Ereignisse auslöst, so dass meine Sammlung geändert wird. Der Handler wird aufgerufen, der das benutzerdefinierte Objekt bearbeitet. Das wiederum löst Ereignisse aus und du bist in einer Schleife. –

+2

Richtig, ich sage, dass das Entwerfen deines Programms so, dass du es absichtlich stoppen musst, in eine Endlosschleife zu gehen, ein ziemlich großer Code-Geruch ist. Gibt es einen Grund, warum Sie nicht nur Änderungen an Ihren Sammlungen über INotifyPropertyChanged vornehmen, oder missverstehe ich Ihren Zweck? – furkle

Antwort

3

Der von Ihnen verwendete Mechanismus - mit einem booleschen Wert, der verfolgt, wenn Aktualisierungen auftreten, und um ihn herum zu blockieren, ist der gebräuchlichste Ansatz.

Persönlich bevorzuge ich es, diese Logik in ein kleines Dienstprogramm zu verpacken, das IDisposable implementiert. Dies macht es einfacher zu garantieren, dass Sie immer nach sich selbst aufräumen.

Ein Dienstprogramm, das Sie für diese verwenden können, würde in etwa so aussehen:

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

Anschließend können Sie schreiben:

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

Dies ist nicht unbedingt kürzer - es ist wahrscheinlich länger zu schreiben, aber Bietet Garantien, dass Sie Ihre Blöcke freigeben, wenn Ausnahmen auftreten. Sie können immer die Unterklasse Guard verwenden, um die Nutzung zu verringern, wenn Sie sie häufig verwenden.