2010-09-29 23 views
7

He utilizado un ObservableCollection con WPF para encuadernar y esto funciona bien. Lo que realmente quiero en este momento es un Diccionario como uno, que tiene una clave que puedo usar, tan efectivamente como "ObservableCollection".WPF: ¿cómo puedo implementar un ObservableCollection <K,T> con una clave (como un diccionario)?

¿Puede sugerir el código que podría utilizarse para proporcionar una ObservableCollection de este tipo? El objetivo es tener una estructura tipo Diccionario a la que pueda enlazar desde WPF.

Gracias

Respuesta

1

Crear una clase que implementa la interfaz IDictionary, INotifyCollectionChanged & interfaces de INotifyPropertyChanged. La clase tendría una instancia de Dictionary que usaría para la implementación de IDictionary (uno de los métodos Add está codificado a continuación como ejemplo). Tanto INotifyCollectionChanged y INotifyProperyChanged requieren la presencia de los acontecimientos, los acontecimientos deben ser despedidos en los puntos apropiados en las funciones de contenedor (de nuevo, consulte el método Add abajo para un ejemplo)

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

Editar:

Tenga en cuenta que una implementación de la interfaz IDictionary directa o indirectamente requeriría que se implementarán tres interfaces adicionales:

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

Dependiendo de sus necesidades puede que no tenga que aplicar toda la IDictionary inte En realidad, si solo va a llamar a un par de métodos, implemente esos métodos y la interfaz IDictionary se convierte en un lujo. Debe implementar las interfaces INotifyCollectionChanged e INotifyPropertyChanged para enlazar a work.Blockquote

+0

poniendo esto en VS Noto que hay muchos más métodos de interfaz que necesitaría implementar, ¿es correcto? – Greg

+0

Sí, si sus requisitos requieren que implemente toda la interfaz IDictionary, consulte mis ediciones –

0

¿Qué pasa algo como:

ObservableCollection<Tuple<string, object>>() 

donde cuerda y objeto y tipos de muestras, por supuesto

+1

Dependiendo del uso, eso puede funcionar. Sin embargo, considere cómo 'encontraría' un elemento por clave cuando use tuplas como esta. Un diccionario puede buscar un valor por clave usando hash y puede ser bastante más rápido que buscar una lista para una clave coincidente. – MPavlak

+0

Has hecho un punto. Sin embargo, usar una colección observable para grandes conjuntos de datos probablemente no sea una buena idea. – eka808

0

ObservableDictonary clase pública: diccionario, INotifyCollectionChanged, INotifyPropertyChanged { evento público 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 Agregar, Eliminar y Eliminar. Debe comprender, si usa el método de extensión o el método simple, que toma el parámetro Dictonary, no verá el cambio, porque en esta situación, el método Agregar o Eliminar usará Dictonary (no Dictonary observable). Por lo tanto, debe dirigir los métodos (Agregar o Eliminar) de ObservableDictonary

Cuestiones relacionadas