Индексатор .NET 4.0 с ObservableCollection - PullRequest
0 голосов
/ 16 ноября 2011

Что такое синтаксис .NET C # для ObservableCollection с индексатором? Я хотел бы ObservableColletion и ссылаться на элементы по порядковому номеру или имени строки. Я знаю, что вы используете это для обозначения индексатора, но я не знаю, как поместить это в ObservableCollection. Спасибо

Спасибо за 4 ответа. Я знаю, как создать и ObservableCollection, и я знаю, как создать индексатор. Я не знаю, как их объединить. Я прошу образец кода для ObservableCollection с порядковым и строковым индексом. Еще раз спасибо

Ответы [ 4 ]

3 голосов
/ 16 ноября 2011

ObservableCollection наследуется от Collection, поэтому она уже имеет индексирование по позициям.

Что касается индексации на основе строк, вы можете взглянуть на реализацию ObservableDictionary для людей.

Лично для повышения производительности я создал коллекцию HashedObservableCollection, основанную на ObservableCollection, которая содержит словарь ключей для индексов для ускорения времени поиска. Переопределив InsertItem, RemoveItem и ClearItems, вы синхронизируете словарь.

В моем примере ключи могут быть любого типа, но мы предполагаем, что ключ никогда не меняется - если элемент заменяется, он заменяется объектом с тем же ключом. Если вы хотите упростить это, вы можете заменить TKey на String.

Код:

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;
        }
    }
}
2 голосов
/ 17 ноября 2011

вот моя идея, надеюсь, это поможет вам найти решение

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 голосов
/ 16 ноября 2011

Я думаю, что это синтаксис, который вы ищете:

  //  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();

Документация для ObservableCollection<T>: http://msdn.microsoft.com/en-us/library/ms668604.aspx

Документация для индексатора (он же свойство 'Item'): http://msdn.microsoft.com/en-us/library/ms132434.aspx

Судя по вашим комментариям, вы ищете ObservableDictionary вместо ObservableCollection..NET не имеет такой встроенной коллекции, но быстрый поиск в Google нашел эти две реализации:

0 голосов
/ 16 ноября 2011

Если я правильно понимаю ваш вопрос, вы можете использовать этот пример

http://msdn.microsoft.com/en-us/library/ms132434.aspx

...