.NET 4.0 索引器与 ObservableCollection

发布于 2024-12-16 19:06:12 字数 270 浏览 0 评论 0原文

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

谢谢4位的回答。我知道如何创建和 ObservableCollection,并且我知道如何创建索引器。我不知道如何将它们结合起来。我要求提供具有序数和字符串索引的 ObservableCollection 的示例代码。 再次感谢

What is the .NET C# syntax for an ObservableCollection with an indexer? I would like an ObservableColletion and refer to the items by ordinal position or a string name. I know you the use this to denote an indexer but I don't know how to put that in an ObservableCollection. Thanks

Thanks for the 4 answers. I know how create and ObservableCollection and I know how to create an indexer. I don't know how to combine them. I am asking for sample code for an ObservableCollection with an ordinal and string index.
Thank again

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

远昼 2024-12-23 19:06:12

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

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

就我个人而言,为了获得更好的性能,我创建了一个从 ObservableCollection 派生的 HashedObservableCollection,其中包含索引键的字典以加快查找时间。通过重写 InsertItem、RemoveItem 和 ClearItems,您可以保持字典同步。

在我的示例中,键可以是任何类型,但我们假设键永远不会改变 - 如果替换某个项目,则会将其替换为具有相同键的对象。如果你想简化这个,你可以用 String 替换 TKey。

代码:

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

ObservableCollection inherits from Collection, so it already has position-based indexing.

For string-based indexing, you can look into peoples implementations of ObservableDictionary.

Personally, for better performance, I've created a HashedObservableCollection deriving from ObservableCollection which contains a Dictionary of keys to indexes to speed lookup time. By overriding InsertItem, RemoveItem, and ClearItems, you keep the dictionary in sync.

In my example, the keys can be of any type but we assume the key never changes - if an item is replaced, it is replaced with an object with the same key. If you want to simplify this, you can replace TKey with 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;
        }
    }
}
此岸叶落 2024-12-23 19:06:12

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

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

here is my idea, hope this helps to find your 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];
    }
  }
}
生死何惧 2024-12-23 19:06:12

如果我正确理解您的问题,您可以使用此示例

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

If i understand your question correctly, you can use this example

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

寂寞笑我太脆弱 2024-12-23 19:06:12

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

  //  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 的文档:http://msdn.microsoft.com/en-us/library/ms668604.aspx

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

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

I think this is the syntax that you are looking for:

  //  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 for ObservableCollection<T>: http://msdn.microsoft.com/en-us/library/ms668604.aspx

Documentation for the Indexer (aka the 'Item' property): http://msdn.microsoft.com/en-us/library/ms132434.aspx

Based on your comments it sounds like you are looking for an ObservableDictionary as opposed to an ObservableCollection. .NET does not have such a collection built in but a quick google search found these two implementations:

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文