2010-09-29 9 views
7

Ho usato una ObservableCollection con WPF per il binding e questo funziona bene. Quello che voglio veramente al momento è un Dizionario come uno, che ha una chiave che posso usare, così efficacemente come "ObservableCollection".WPF - Come posso implementare una ObservableCollection <K,T> con una chiave (come un dizionario)?

Potete suggerire il codice che potrebbe essere utilizzato per fornire tale ObservableCollection? L'obiettivo è avere una struttura di tipo Dizionario che possa essere associata a WPF.

Grazie

risposta

1

Creare una classe che implementa l'IDictionary, INotifyCollectionChanged & interfacce INotifyPropertyChanged. La classe avrebbe un'istanza di Dizionario che userebbe per l'implementazione di IDictionary (uno dei metodi Add è codificato di seguito come esempio). Sia INotifyCollectionChanged e INotifyProperyChanged richiedono la presenza di eventi, questi eventi dovrebbero essere licenziati in punti appropriati nelle funzioni wrapper (ancora una volta, consultare il metodo Add sotto per un esempio)

class ObservableDictionary<TKey, TValue> : IDictionary, INotifyCollectionChanged, INotifyPropertyChanged 
{ 
    private Dictionary<TKey, TValue> mDictionary; 
    // Methods & Properties for IDictionary implementation would defer to mDictionary: 
    public void Add(TKey key, TValue value){ 
     mDictionary.Add(key, value); 
     OnCollectionChanged(NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, value) 
     return; 
    } 
    // Implementation of INotifyCollectionChanged: 
    public event NotifyCollectionChangedEventHandler CollectionChanged; 
    protected void OnCollectionChanged(NotifyCollectionChangedEventArgs args){ 
     // event fire implementation 
    } 
    // Implementation of INotifyProperyChanged: 
    public event ProperyChangedEventHandler ProperyChanged; 
    protected void OnPropertyChanged(PropertyChangedEventArgs args){ 
     // event fire implementation 
    } 
} 

Edit:

Nota che un implementazione dell'interfaccia IDictionary direttamente o indirettamente richiederebbe che tre interfacce aggiuntive essere attuate:

ICollection<KeyValuePair<TKey,TValue>> 
IEnumerable<KeyValuePair<TKey,TValue>> 
IEnumerable. 

a seconda delle necessità si può non essere necessario implementare l'intero IDictionary inte rface, se stai solo chiamando un paio di metodi allora implementa questi metodi e l'interfaccia IDictionary diventa un lusso. È necessario implementare le interfacce INotifyCollectionChanged e INotifyPropertyChanged affinché l'associazione funzioni comunque.Blockquote

+0

mettendo questo in VS. Nota che ci sono molti più metodi di interfaccia che avrebbero bisogno di implementazione - è corretto? – Greg

+0

Sì, se i requisiti richiedono l'implementazione dell'intera interfaccia IDictionary, vedere le mie modifiche –

0

Che dire qualcosa come:

ObservableCollection<Tuple<string, object>>() 

dove stringa e oggetto e tipi di campioni, naturalmente

+1

A seconda dell'utilizzo, potrebbe funzionare. Tuttavia, considera come dovresti "trovare" un elemento per chiave quando usi tuple come questo. Un dizionario può cercare un valore per chiave usando l'hashing e può essere un po 'più veloce della ricerca di un elenco per una chiave corrispondente. – MPavlak

+0

Hai fatto un punto. Tuttavia, l'utilizzo di una raccolta osservabile per enormi set di dati non è probabilmente una buona idea. – eka808

0

public class ObservableDictonary: Dizionario, INotifyCollectionChanged, INotifyPropertyChanged { evento pubblico NotifyCollectionChangedEventHandler CollectionChanged;

public event PropertyChangedEventHandler PropertyChanged; 

    public new void Add(TKey key, TValue value) 
    { 
     base.Add(key, value); 
     if (!TryGetValue(key, out _)) return; 
     var index = Keys.Count; 
     OnPropertyChanged(nameof(Count)); 
     OnPropertyChanged(nameof(Values)); 
     OnCollectionChanged(NotifyCollectionChangedAction.Add, value, index); 
    } 

    public new void Remove(TKey key) 
    { 
     if (!TryGetValue(key, out var value)) return; 
     var index = IndexOf(Keys, key); 
     OnPropertyChanged(nameof(Count)); 
     OnPropertyChanged(nameof(Values)); 
     OnCollectionChanged(NotifyCollectionChangedAction.Remove, value, index); 
     base.Remove(key); 
    } 

    public new void Clear() 
    { 

    } 

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs e) 
    { 
     PropertyChanged?.Invoke(this, e); 
    } 

    protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e) 
    { 
     CollectionChanged?.Invoke(this, e); 
    } 

    private void OnPropertyChanged(string propertyName) 
    { 
     OnPropertyChanged(new PropertyChangedEventArgs(propertyName)); 
    } 

    private void OnCollectionChanged(NotifyCollectionChangedAction action, object item) 
    { 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item)); 
    } 

    private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index) 
    { 
     OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index)); 
    } 

    private int IndexOf(KeyCollection keys, TKey key) 
    { 
     var index = 0; 
     foreach (var k in keys) 
     { 
      if (Equals(k, key)) 
       return index; 
      index++; 
     } 
     return -1; 
    } 
} 

I ovveride Aggiungi, Rimuovi e Cancella. Devi capire, se usi un metodo di estensione o un metodo semplice, che prende il parametro Dictonary, non vedrai cambiare, perché in questa situazione, il metodo Aggiungi/Rimuovi utilizzerà Dictonary (not ObservableDictonary). Quindi devi indirizzare i metodi (Aggiungi o Rimuovi) di ObservableDictonary

Problemi correlati