2011-11-16 7 views
0

Quelle est la syntaxe .NET C# pour une ObservableCollection avec un indexeur? Je voudrais un ObservableColletion et se référer aux articles par position ordinale ou un nom de chaîne. Je vous connais l'utiliser pour désigner un indexeur mais je ne sais pas comment le mettre dans un ObservableCollection. Merci.NET 4.0 Indexer avec ObservableCollection

Merci pour les 4 réponses. Je sais comment créer et ObservableCollection et je sais comment créer un indexeur. Je ne sais pas comment les combiner. Je demande un exemple de code pour une ObservableCollection avec un index ordinal et string. Merci encore

Répondre

3

ObservableCollection hérite de la collection, il a déjà indexation basée sur la position. Pour l'indexation à base de chaîne, vous pouvez consulter les implémentations de ObservableDictionary.

Personnellement, pour de meilleures performances, j'ai créé une HashedObservableCollection dérivée de ObservableCollection qui contient un dictionnaire de clés pour indexer le temps de recherche. En substituant InsertItem, RemoveItem et ClearItems, vous maintenez le dictionnaire en synchronisation. Dans mon exemple, les clés peuvent être de n'importe quel type mais nous supposons que la clé ne change jamais - si un élément est remplacé, il est remplacé par un objet avec la même clé. Si vous voulez simplifier cela, vous pouvez remplacer TKey par String.

code:

using System; 
using System.Linq; 
using System.Collections.Generic; 
using System.Collections.ObjectModel; 

namespace foson.Utils 
{ 
    /// <summary> 
    /// Represents BindableCollection indexed by a dictionary to improve lookup/replace performance. 
    /// </summary> 
    /// <remarks> 
    /// Assumes that the key will not change and is unique for each element in the collection. 
    /// Collection is not thread-safe, so calls should be made single-threaded. 
    /// </remarks> 
    /// <typeparam name="TValue">The type of elements contained in the BindableCollection</typeparam> 
    /// <typeparam name="TKey">The type of the indexing key</typeparam> 
    public class HashedBindableCollection<TValue, TKey> : ObservableCollection<TValue> 
    { 

     protected internal Dictionary<TKey, int> indecies = new Dictionary<TKey, int>(); 
     protected internal Func<TValue, TKey> _keySelector; 

     /// <summary> 
     /// Create new HashedBindableCollection 
     /// </summary> 
     /// <param name="keySelector">Selector function to create key from value</param> 
     public HashedBindableCollection(Func<TValue, TKey> keySelector) 
      : base() 
     { 
      if (keySelector == null) throw new ArgumentException("keySelector"); 
      _keySelector = keySelector; 
     } 

     #region Protected Methods 
     protected override void InsertItem(int index, TValue item) 
     { 
      var key = _keySelector(item); 
      if (indecies.ContainsKey(key)) 
       throw new DuplicateKeyException(key.ToString()); 

      if (index != this.Count) 
      { 
       foreach (var k in indecies.Keys.Where(k => indecies[k] >= index).ToList()) 
       { 
        indecies[k]++; 
       } 
      } 

      base.InsertItem(index, item); 
      indecies[key] = index; 

     } 

     protected override void ClearItems() 
     { 
      base.ClearItems(); 
      indecies.Clear(); 
     } 


     protected override void RemoveItem(int index) 
     { 
      var item = this[index]; 
      var key = _keySelector(item); 

      base.RemoveItem(index); 

      indecies.Remove(key); 

      foreach (var k in indecies.Keys.Where(k => indecies[k] > index).ToList()) 
      { 
       indecies[k]--; 
      } 
     } 
     #endregion 

     public virtual bool ContainsKey(TKey key) 
     { 
      return indecies.ContainsKey(key); 
     } 

     /// <summary> 
     /// Gets or sets the element with the specified key. If setting a new value, new value must have same key. 
     /// </summary> 
     /// <param name="key">Key of element to replace</param> 
     /// <returns></returns> 
     public virtual TValue this[TKey key] 
     { 

      get { return this[indecies[key]]; } 
      set 
      { 
       //confirm key matches 
       if (!_keySelector(value).Equals(key)) 
        throw new InvalidOperationException("Key of new value does not match"); 

       if (!indecies.ContainsKey(key)) 
       { 
        this.Add(value); 
       } 
       else 
       { 
        this[indecies[key]] = value; 
       } 
      } 
     } 

     /// <summary> 
     /// Replaces element at given key with new value. New value must have same key. 
     /// </summary> 
     /// <param name="key">Key of element to replace</param> 
     /// <param name="value">New value</param> 
     /// 
     /// <exception cref="InvalidOperationException"></exception> 
     /// <returns>False if key not found</returns> 
     public virtual bool Replace(TKey key, TValue value) 
     { 
      if (!indecies.ContainsKey(key)) return false; 
      //confirm key matches 
      if (!_keySelector(value).Equals(key)) 
       throw new InvalidOperationException("Key of new value does not match"); 

      this[indecies[key]] = value; 
      return true; 

     } 

     public virtual bool Remove(TKey key) 
     { 
      if (!indecies.ContainsKey(key)) return false; 

      this.RemoveAt(indecies[key]); 
      return true; 

     } 

    } 
    public class DuplicateKeyException : Exception 
    { 

     public string Key { get; private set; } 
     public DuplicateKeyException(string key) 
      : base("Attempted to insert duplicate key " + key + " in collection") 
     { 
      Key = key; 
     } 
    } 
} 
+0

J'ai besoin de plus de détails.Syntaxe C# pour un ObservableCollection avec un index ordinal et un index de chaîne. – Paparazzi

+0

jetez un coup d'œil à la méthode 'public virtual TValue this [TKey key]'. Vous pouvez surcharger plusieurs fois la fonction de l'indexeur ('public XXX this [YYY]') tant que chaque surcharge a un type de paramètre différent. – foson

+0

Génial! Vraiment comme ce constructeur. Je suppose que la partie ordinale est prise en charge en héritant de ObservableCollection? – Paparazzi

0

Je pense que c'est la syntaxe que vous recherchez:

// create a generic ObservableCollection - I used object, but you can use any Type 
    var collection = new ObservableCollection<object>(); 

    // set the item at the index. 
    collection[0] = new object(); 

Documentation pour ObservableCollection<T> : http://msdn.microsoft.com/en-us/library/ms668604.aspx

Documentation pour l'indexeur (aka la propriété 'Item'): http://msdn.microsoft.com/en-us/library/ms132434.aspx

Basé sur vos commentaires il semble que vous cherchez un ObservableDictionary par opposition à un ObservableCollection. .NET ne dispose pas d'une telle collection construite en mais une recherche rapide Google trouvé ces deux implémentations:

+0

Ce lien est l'indice ordinal pour une collection. La question est la syntaxe C# pour ObservableCollection avec l'index ordinal et string. – Paparazzi

+0

@BalamBalam, La classe 'ObservableCollection' n'est pas indexée par une valeur de chaîne. Vous devez gérer un tableau de chaînes avec des index correspondant à l'index de la collection observable. – smartcaveman

+0

@BalamBalam, s'il vous plaît voir la mise à jour – smartcaveman

2

voici mon idée, espérons que cela aide à trouver votre solution

using System.Collections.ObjectModel; 

namespace WPFValidation 
{ 
    public class CustomObservableCollection<T> : ObservableCollection<T> 
    { 
    public T this[string key] { 
     get { 
     // you must implement some code to do this one 
     T item = GetItemWithAKey(key); 
     return item; 
     } 
     set { 
     T item = GetItemWithAKey(key); 
     if (item != null) { 
      // set the given value toi the item 
      this.SetItemValue(item, value); 
     } 
     } 
    } 

    private T GetItemWithAKey(string key) { 
     // find the item with teh given key 
     return default(T); 
    } 
    } 

    public class TestClass 
    { 
    public TestClass() { 
     var coll = new CustomObservableCollection<CustomKeyedClass>(); 
     coll.Add(new CustomKeyedClass("One")); 
     coll.Add(new CustomKeyedClass("Two")); 
     var item = coll["One"]; 
     var item2 = coll[1]; 
    } 
    } 
} 
+0

GetItemsWithKey est l'endroit où je dessine un blanc. +1 La réponse de Foson est tout ce dont j'ai besoin (je pense). – Paparazzi

+0

oui, c'est une bonne solution! – punker76