0

带有索引器的 ObservableCollection 的 .NET C# 语法是什么?我想要一个 ObservableColletion 并按序号位置或字符串名称引用项目。我知道您使用它来表示索引器,但我不知道如何将它放入 ObservableCollection。谢谢

感谢您的4个答案。我知道如何创建和 ObservableCollection,也知道如何创建索引器。我不知道如何将它们结合起来。我要求提供带有序号和字符串索引的 ObservableCollection 的示例代码。再次感谢

4

4 回答 4

3

ObservableCollection 继承自 Collection,因此它已经具有基于位置的索引。

对于基于字符串的索引,您可以查看人们对 ObservableDictionary 的实现。

就个人而言,为了获得更好的性能,我创建了一个派生自 ObservableCollection 的 HashedObservableCollection,其中包含索引键字典以加快查找时间。通过覆盖 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;
        }
    }
}
于 2011-11-16T19:17:08.233 回答
2

这是我的想法,希望这有助于找到您的解决方案

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];
    }
  }
}
于 2011-11-16T20:01:50.070 回答
0

我认为这是您正在寻找的语法:

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

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

索引器的文档(又名“项目”属性):http: //msdn.microsoft.com/en-us/library/ms132434.aspx

根据您的评论,听起来您正在寻找一个ObservableDictionary而不是一个ObservableCollection. .NET 没有内置这样的集合,但通过谷歌快速搜索发现了这两个实现:

于 2011-11-16T19:14:51.123 回答
0

如果我正确理解你的问题,你可以使用这个例子

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

于 2011-11-16T19:14:20.560 回答