问题
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
回答1:
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;
}
}
}
回答2:
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];
}
}
}
回答3:
If i understand your question correctly, you can use this example
http://msdn.microsoft.com/en-us/library/ms132434.aspx
回答4:
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:
http://blogs.microsoft.co.il/blogs/shimmy/archive/2010/12/26/observabledictionary-lt-tkey-tvalue-gt-c.aspx
http://uberpwn.wordpress.com/2011/03/12/my-c-observabledictionary/
来源:https://stackoverflow.com/questions/8157140/net-4-0-indexer-with-observablecollection