2014-10-28 10 views
5

Qual è il modo migliore per sincronizzare 2 insiemi di dati tramite Binding?TwoWay Collection Binding Sync/Lock

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

Ora la mia domanda è, quando ricevo un aggiornamento da una raccolta (ad esempio eventi Source.CollectionChanged) ho bisogno di chiamare i TargetSetters personalizzati, e ignorare gli eventi chiamati originatesi dal mio aggiornamento.

E anche l'altro modo, quando gli eventi personalizzati di destinazione vengono generati, devo aggiornare l'origine, ma ignoro l'evento CollectionChanged.

Al momento, sto mantenendo un riferimento ai miei gestori e rimuoverlo prima di aggiornare qualsiasi raccolta. per esempio.

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

ho visto che è possibile utilizzare un'istruzione if per verificare se gli aggiornamenti sono dalla fonte, e se sono ignorarli. per esempio.

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

Dopo Google + SO Search è tornato con niente, volevo vedere come altre persone stanno facendo questo, e c'è qualcosa di veramente semplice che mi manca qui che risolve questo problema? (So ​​che gli esempi non sono thread-safe)

In caso contrario, qual è il modo preferito? Rimozione e collegamento di gestori o impostazione di una bandiera booleana? Ciò che è più performante (sì, so che è molto improbabile che causi un collo di bottiglia ma per curiosità)

La ragione che sto chiedendo è perché, attualmente sto implementando i comportamenti associati e per ogni comportamento, sto creando 2 set di dizionari che contengono i riferimenti ai gestori per ogni oggetto in quanto lo stato deve essere passato in giro.

Non riesco a trovare il codice sorgente per il meccanismo di binding delle classi .NET Binding, per vedere come MS l'ha implementato. Se qualcuno ha un link a quelli sarebbe molto apprezzato.

+0

Scusa, potrei mancare qualcosa, ma perché il tuo progetto richiede di ignorare alcuni degli eventi che stai sparando ogni volta che qualcosa cambia? Non riesco davvero a capire cosa stai cercando di realizzare. Puoi forse dire qual è il problema che stai cercando di risolvere? – furkle

+0

Perché se ti iscrivi ad entrambi i lati, riceverai le notifiche da entrambi i lati. Causando un ciclo infinito. Per esempio.Customibject solleva l'evento che è cambiato, il mio gestore viene chiamato e modifica la collezione vincolata, che a sua volta aumenta gli eventi modificati, quindi viene chiamato il gestore della mia collezione modificato che modifica l'oggetto personalizzato. Questo di nuovo aumenta gli eventi e tu sei in un ciclo –

+2

Giusto, sto dicendo che progettare il tuo programma in modo tale da impedirlo deliberatamente di entrare in un loop infinito è un odore di codice piuttosto grande. C'è una ragione per cui non stai semplicemente gestendo le modifiche alle tue raccolte tramite INotifyPropertyChanged, o sto fraintendendo il tuo scopo? – furkle

risposta

3

Il meccanismo che si sta utilizzando: avere un booleano che tiene traccia degli aggiornamenti e bloccarli è l'approccio più comune.

Personalmente, preferisco racchiudere quella logica in una piccola utility che implementa IDisposable. Questo rende più facile garantire che ti ripulisci sempre da solo.

Un'utility è possibile utilizzare per questo sarebbe simile:

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

È quindi possibile scrivere:

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

Questo non è necessariamente più breve - la sua, probabilmente più tempo per scrivere, ma fornisce garanzie che rilascerai i tuoi blocchi se si verificano eccezioni. Puoi sempre sottoclasse Guard per ridurre l'utilizzo se lo utilizzi spesso.

Problemi correlati