2010-11-29 8 views
8

Quando si utilizza l'associazione WPF, ovviamente non è possibile fare qualcosa sulla linea MyCollection = new CollectionType<Whatever>(WhateverQuery()); poiché i collegamenti hanno un riferimento alla vecchia raccolta. Il mio workaround finora è stato MyCollection.Clear(); seguito da un foreach che fa MyCollection.Add(item); - il che è piuttosto negativo sia per le prestazioni che per l'estetica.WPF: sostituzione del contenuto della raccolta del database senza Cancella/Aggiungi

ICollectionView, sebbene piuttosto pulito, non risolve il problema in quanto è SourceCollection proprietà è di sola lettura; peccato, dal momento che sarebbe stata una soluzione semplice e facile.

In che modo altre persone gestiscono questo problema? Va detto che sto facendo MVVM e quindi non posso rovistare attraverso i collegamenti dei controlli individuali. Suppongo che potrei realizzare un wrapper attorno allo ObservableCollection con un metodo ReplaceSourceCollection(), ma prima di percorrere quella strada vorrei sapere se c'è qualche altra buona pratica.

EDIT:

Per WinForms, vorrei associare i controlli nei confronti di un BindingSource, che mi permette di aggiornare semplicemente è DataSource proprietà e chiamo il metodo ResetBindings() - presto, alla base di raccolta in modo efficiente cambiato. Mi sarei aspettato che il databinding di WPF supportasse uno scenario simile fuori dagli schemi?

Codice di esempio (pseudo-ish): il controllo WPF (ListBox, DataGrid, qualsiasi cosa vogliate) è associato alla proprietà Users. Mi rendo conto che le collezioni devono essere in sola lettura per evitare i problemi dimostrati da ReloadUsersBad(), ma poi il codice male per questo esempio evidentemente non sarebbe compilare :)

public class UserEditorViewModel 
{ 
    public ObservableCollection<UserViewModel> Users { get; set; } 

    public IEnumerable<UserViewModel> LoadUsersFromWhateverSource() { /* ... */ } 

    public void ReloadUsersBad() 
    { 
     // bad: the collection is updated, but the WPF control is bound to the old reference. 
     Users = new ObservableCollection<User>(LoadUsersFromWhateverSource()); 
    } 

    public void ReloadUsersWorksButIsInefficient() 
    { 
     // works: collection object is kept, and items are replaced; inefficient, though. 
     Users.Clear(); 
     foreach(var user in LoadUsersFromWhateverSource()) 
      Users.Add(user); 
    } 

    // ...whatever other stuff. 
} 
+0

puoi inserire un codice? – TalentTuner

+0

+1 buona domanda. Non ho fatto nulla in WPF per un po ', ma un altro framework in un linguaggio diverso ha concetti simili e risolve questo problema interrompendo il ciclo di esecuzione, modificando un gran numero di proprietà e quindi stappando il ciclo di esecuzione. Sto cercando qualcosa di simile. –

risposta

4

Se l'oggetto MyCollection è degli strumenti INotifyPropertyChanged, è possibile semplicemente sostituire la raccolta.

Un esempio:

public class MyClass : INotifyPropertyChanged 
{ 
    public event PropertyChangedEventHandler PropertyChanged; 
    private ObservableCollection<Whatever> _myCollection; 

    private void NotifyChanged(string property) 
    { 
     if (PropertyChanged != null) 
      PropertyChanged(this, new PropertyChangedEventArgs(property)); 
    } 

    public ObservableCollection<Whatever> MyCollection 
    { 
     get 
     { 
      return _myCollection; 
     } 
     set 
     { 
      if (!ReferenceEquals(_myCollection, value)) 
      { 
       _myCollection = value; 
       NotifyChanged("MyCollection"); 
      } 
     } 
    } 
} 

Con questo, quando si assegna una collezione, WPF rileva questo e tutto viene aggiornato.

Ecco come risolverei questo.

+0

Certo ... sono abbastanza sicuro di averlo già dovuto fare prima. –

+0

D'oh!Doveva essere qualcosa di semplice e ovvio, no? : P – snemarch

+0

Nessun problema, felice di poterti aiutare. –

1

Il link qui sotto spiega come implementare un metodo AddRange.

http://blogs.msdn.com/b/nathannesbit/archive/2009/04/20/addrange-and-observablecollection.aspx

Sembra che tu sei bloccato con l'attuazione di una sottoclasse che gestisce questo caso correttamente.

Apparentemente, alcuni controlli non supportano le notifiche di modifica delle raccolte in batch. Almeno non l'hanno fatto quando quell'articolo è stato scritto. Anche se ora dovresti avere un po 'più di informazioni se vuoi approfondire ulteriormente.

+0

Articolo decente per la gestione degli aggiornamenti in batch (anziché la sostituzione completa) - sgradevole che 'ListCollectionView' supporti solo gli aggiornamenti di singoli elementi: | – snemarch

Problemi correlati