2013-08-01 15 views
6
public class Alpha 
{ 
    public ObservableCollection<Beta> Items { get; set; } 

    public Alpha() 
    { 
     Items = new ObservableCollection<Beta>(); 
    } 

    public void DoSomething() 
    { 
     Items = GetNewItems(); // whenever I do this, Items gets a new referene, 
           // so every WPF binding (e.g. datagrids) are broken 
    } 

    public ObservableCollection<Beta> GetNewItems() 
    { 
     var ret = new ObservableCollection<Beta>(); 
     // some logic for getting some items from somewhere, and populating ret 
     return ret; 
    } 
} 

Come posso sostituire l'intero contenuto della Items con il valore di ritorno di GetNewItems() senza:sostituire l'intera ObservableCollection con un altro ObservableCollection

  1. Rompere le associazioni.

  2. È necessario scorrere gli articoli e copiarli uno ad uno nell'altra raccolta?

+0

Hey @ user2270404, è stato fatto in .NET 4.5? –

+0

@The Red Lou: No, è stato fatto in 4.0 –

+0

Beh, volevo solo farti sapere che ho aggiornato la mia risposta in base al feedback se ti interessa dare un'occhiata. Ho trovato altri modi per realizzarlo e creare degli esempi, ma il terzo richiede .NET 4.5. –

risposta

7

avete alcune opzioni:

  1. Attuare INotifyPropertyChanged in modo da poter informare l'utente che il valore degli oggetti è cambiato. Questo non utilizza il fatto che INotifyCollectionChanged è implementato su ObservableCollection. Funzionerà, ma sconfigge lo scopo di utilizzare ObservableCollection in primo luogo. Questo non è raccomandato ma funziona.
  2. Utilizza Aggiunta del ObservableCollection/Rimuovi metodi/Modifica/Update per modificarlo in collaborazione con il Dispatcher.
    • Nota: senza il Dispatcher, si otterrà un NotSupportedException perché CollectionViews non supportano modifiche alla loro SourceCollection da un thread diverso dal thread Dispatcher.
  3. Utilizzare i metodi Aggiungi/Rimuovi/Modifica/Aggiorna di ObservableCollection per modificarlo in combinazione con BindingOperations.EnableCollectionSynchronization. Consigliato
    • Nota: questo è disponibile solo in .NET 4.5.
    • Questa è un'alternativa all'utilizzo del Dispatcher evitando l'eccezione NotSupportedException.
    • Example

numeri 2 e 3, per quanto riguarda la tua domanda, si traducono in compensazione gli elementi esistenti (Clear()) e poi aggiungendo (add()) gli oggetti restituiti con qualsiasi metodo voglio - vedere l'esempio per # 3. La chiave è che la cancellazione e tutte le aggiunte devono essere eseguite con Dispatcher (2) o chiamando BindingOperations.EnableCollectionSynchronization. Buona fortuna!

Riferimento: Reed Copsey Answer - StackOverflow

+1

Questo non sfrutta il fatto che viene utilizzata una raccolta di dati osservabile. – Shoe

+0

Come può essere migliorato allora? –

+0

Concordo con Shoe. Non ha molto senso aggiungere un secondo meccanismo di notifica quando quello esistente funzionerà correttamente e produrrà un codice più pulito e più gestibile. – denver

1

ObservableCollection implementa INotifyCollectionChanged, che aggiornerà binding quando articoli vengono aggiunti o rimossi. Tutto ciò che serve qui è cancellare la lista per l'evento CollectionChanged da sparare.

public void GetNewItems() 
{ 
    Items.Clear(); 

    // some logic for getting some items from somewhere, and populating ret 

} 
+1

Nota: questo _can_ causa una NotSupportedException. –

+0

@TheRedLou Puoi spiegarlo? Non ne sono consapevole. – Shoe

+0

@TheRedLou Non c'è niente riguardo a questa domanda che parla di un thread non-ui. – Shoe

2

si può anche fare la propria classe che estenderà l'ObservableCollection, ecco un esempio con le notifiche ordinato:

https://github.com/jamesmontemagno/mvvm-helpers/blob/master/MvvmHelpers/ObservableRangeCollection.cs

sto usando più semplice implementazione di sopra (non ho paragonato l'aspetto di notifica ancora):

using System; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 
using System.Collections.Specialized; 
using System.ComponentModel; 
using System.Runtime.CompilerServices; 
using BaseLibrary.Properties; 

namespace BaseLibrary 
{ 
/// <summary> 
/// Represents a dynamic data collection that provides notifications when items get added, removed, or when the whole list is refreshed. 
/// </summary> 
/// <typeparam name="T"></typeparam> 
public class ObservableCollectionEx<T> : ObservableCollection<T> 
{ 
    //INotifyPropertyChanged interited from ObservableCollection<T> 
    #region INotifyPropertyChanged 

    protected override event PropertyChangedEventHandler PropertyChanged; 

    [NotifyPropertyChangedInvocator] 
    public void OnPropertyChanged([CallerMemberName] string propertyName = null) 
    { 
     PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName)); 
    } 

    #endregion INotifyPropertyChanged 

    /// <summary> 
    /// Adds the elements of the specified collection to the end of the ObservableCollection(Of T). 
    /// </summary> 
    public void AddRange(IEnumerable<T> collection) 
    { 
     if (collection == null) throw new ArgumentNullException(nameof(collection)); 

     foreach (var i in collection) Items.Add(i); 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 

    /// <summary> 
    /// Removes the first occurence of each item in the specified collection from ObservableCollection(Of T). 
    /// </summary> 
    public void RemoveRange(IEnumerable<T> collection) 
    { 
     if (collection == null) throw new ArgumentNullException(nameof(collection)); 

     foreach (var i in collection) Items.Remove(i); 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 

    /// <summary> 
    /// Clears the current collection and replaces it with the specified item. 
    /// </summary> 
    public void Replace(T item) 
    { 
     Replace(new T[] { item }); 
    } 

    /// <summary> 
    /// Replaces all elements in existing collection with specified collection of the ObservableCollection(Of T). 
    /// </summary> 
    public void Replace(IEnumerable<T> collection) 
    { 
     if (collection == null) throw new ArgumentNullException(nameof(collection)); 

     Items.Clear(); 
     foreach (var i in collection) Items.Add(i); 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset)); 
    } 

    /// <summary> 
    /// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class. 
    /// </summary> 
    public ObservableCollectionEx() 
     : base() { } 

    /// <summary> 
    /// Initializes a new instance of the System.Collections.ObjectModel.ObservableCollection(Of T) class that contains elements copied from the specified collection. 
    /// </summary> 
    /// <param name="collection">collection: The collection from which the elements are copied.</param> 
    /// <exception cref="System.ArgumentNullException">The collection parameter cannot be null.</exception> 
    public ObservableCollectionEx(IEnumerable<T> collection) 
     : base(collection) { } 
} 

}

Problemi correlati