#133 - Una collezione avanzata per il data binding di WPF
di Cristian Civera, in Windows Presentation Foundation, 18 settembre 2009
Archiviato in: .NET Framework, .NET Framework 3.0, .NET Framework 3.5, Windows Presentation Foundation
Il motore di data binding di Windows Presentation Foundation per poter essere sfruttato appieno, necessita di collezioni di dati che implementino l'interfaccia INotifyCollectionChanged. In questo modo, aggiungendo o togliendo elementi dalla lista, il motore si accorge degli elementi cambiati e cambia di conseguenza l'interfaccia.
Nello script #25, si è visto come implementare questa interfaccia e come la classe ObservableCollection effettua già questo lavoro. Essa però non dispone di alcune funzionalità utili in casi reali come la possibilità di inibire gli eventi per una serie di operazioni sulla collezione. Ad ogni metodo di Add, Remove, Clear infatti, viene scatenato l'evento sulle proprietà Count, Item[] e la rispettiva NotifyCollectionChangedAction. Questo significa che se dobbiamo inserire parecchi elementi, ad ogni modifica della lista, scattano delle operazioni sui controlli di lista associati.
E' possibile creare però una propria classe con un metodo StartDeferRefresh per aprire una finestra in cui manipolare la lista come si vuole, senza scatenare eventi, per poi ripristinare l'operazione quando si ha terminato.
Si definisce quindi una propria classe che sovrascriva i metodi OnPropertyChanged e OnCollectionChanged in modo che in funzione di una campo privato, questi lancino o meno gli eventi.
public class ObservableCollectionEx<T> : ObservableCollection<T> { private bool _deferRefresh; protected override void OnPropertyChanged(System.ComponentModel.PropertyChangedEventArgs e) { if (!_deferRefresh) base.OnPropertyChanged(e); } protected override void OnCollectionChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) { if (!_deferRefresh) base.OnCollectionChanged(e); } public bool DeferRefresh { get { return _deferRefresh; } private set { _deferRefresh = value; } }
Il metodo StartDeferRefresh non fa altro che impostare il campo privato e restituire un oggetto IDisposable. Questo permette di ripristinare la generazione degli eventi usando il costrutto try/finally o la using.
public IDisposable StartDeferRefresh(bool raiseEvents) { this.DeferRefresh = true; return new Disp(this, raiseEvents); }
La classe interna DeferDispose riceve i riferimenti alla collezione stessa e un parametro per indicare se scatenare al termine gli eventi, dando per scontato che la lista sia cambiata.
protected class Disp : IDisposable { private ObservableCollectionEx<T> parent; private readonly bool raiseEvents; public Disp(ObservableCollectionEx<T> parent, bool raiseEvents) { this.parent = parent; this.raiseEvents = raiseEvents; } void IDisposable.Dispose() { this.parent.DeferRefresh = false; // Genero gli eventi, se richiesto if (raiseEvents) { parent.OnPropertyChanged(new PropertyChangedEventArgs("Count")); parent.OnPropertyChanged(new PropertyChangedEventArgs("Item[]")); parent.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); } } }
A questo punto l'utilizzo è piuttosto rapido perché non si deve far altro che chiamare lo StartDeferRefresh con il costrutto using e manipolare la lista.
ObservableCollectionEx<String> values = new ObservableCollectionEx<String>(); using (values.StartDeferRefresh(true)) { values.Add("item 1"); values.Add("item 1"); }
Questa tecnica infine può essere sfruttata anche per invocare gli eventi sul thread principale, per risolvere la problematica descritta nello script #25, andando ad invocare il Dispose sul thread UI, anche se la manipolazione della lista viene fatta in un thread differente.
Approfondimenti
-
.NET Framework 4.0 beta 1: Workflow Foundation 4.0
-
Real Code Day 4.0: Agenda (quasi) completata!
-
#136 - Utilizzare LINQ per raggruppare gli application pool di IIS in base al tipo di pipeline
-
Costruire una chat per Silverlight con il PollingDuplexHttpBinding
-
#141 - Alleggerire le applicazioni WPF sfruttando gli oggetti Freezable
-
#159 - Gestire code di operazioni con un Dispatcher personalizzato
-
#155 - Gestire e ottimizzare messaggi di grandi dimensioni in WCF
-
#987 - La gestione della cache con il controllo LinqDataSource di ASP.NET 3.5
-
#50 - Caricare un oggetto XAML da file remoto in Silverlight 2.0
-
.NET Framework 4.0 Beta 1: Parallel FX
-
#163 - Personalizzare le installazioni con Windows Installer
-
#111 - Personalizzare la serializzazione delle entità di ADO.NET Data Services

















Per inserire un commento, devi avere un account.
Fai il login e torna a questa pagina, oppure registrati alla nostra community.