210 lines
5.5 KiB
C#
210 lines
5.5 KiB
C#
using System.Collections.Generic;
|
|
using JD.Collections.Interfaces;
|
|
using JD.Kernel.StaticHelpers;
|
|
|
|
namespace JD.Collections
|
|
{
|
|
/// <summary>
|
|
/// A Keyed collection that you can listen to through the CollectionChanged event.
|
|
/// </summary>
|
|
public abstract class ObservableKeyedList<TKey, TValue> : ObservableList<TValue>, IObservableKeyedList<TKey, TValue>
|
|
{
|
|
#region Variables
|
|
|
|
private readonly KeyedCollection m_dictionary;
|
|
|
|
#endregion
|
|
|
|
#region Constructor
|
|
|
|
/// <summary>
|
|
/// Ctor
|
|
/// </summary>
|
|
protected ObservableKeyedList()
|
|
{
|
|
m_dictionary = new KeyedCollection(this);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Override default key Comparer
|
|
/// </summary>
|
|
/// <param name="comparer"></param>
|
|
protected ObservableKeyedList(IEqualityComparer<TKey> comparer)
|
|
{
|
|
m_dictionary = new KeyedCollection(this, comparer);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Methods
|
|
|
|
/// <summary>
|
|
/// Get value from key.
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <returns></returns>
|
|
/// <remarks>Does not throw when the key is not contained.</remarks>
|
|
public virtual TValue this[TKey key]
|
|
{
|
|
get
|
|
{
|
|
if (Equals(key, null))
|
|
{
|
|
return default(TValue);
|
|
}
|
|
|
|
TValue value;
|
|
m_dictionary.TryGetValue(key, out value);
|
|
return value;
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Removes the item with the given <paramref name="key"/>.
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <returns></returns>
|
|
public bool Remove(TKey key)
|
|
{
|
|
TValue value;
|
|
if (!m_dictionary.TryGetValue(key, out value))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return Remove(value);
|
|
}
|
|
|
|
/// <summary>
|
|
/// When implemented in a derived class, extracts the key from the specified element.
|
|
/// </summary>
|
|
/// <param name="value"></param>
|
|
/// <returns></returns>
|
|
protected abstract TKey GetKeyForItem(TValue value);
|
|
|
|
/// <summary>
|
|
/// Whether the keyed collection contains the key.
|
|
/// </summary>
|
|
/// <param name="key"></param>
|
|
/// <returns></returns>
|
|
public virtual bool ContainsKey(TKey key)
|
|
{
|
|
if (Equals(key, null))
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return m_dictionary.ContainsKey(key);
|
|
}
|
|
|
|
/// <summary>
|
|
/// True if it contains the item.
|
|
/// </summary>
|
|
/// <param name="item"></param>
|
|
/// <returns></returns>
|
|
public override bool Contains(TValue item)
|
|
{
|
|
return !Equals(item, null) && ContainsKey(GetKeyForItem(item));
|
|
}
|
|
|
|
/// <summary>
|
|
/// Overridden.
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
/// <param name="item"></param>
|
|
protected override void InsertItem(int index, TValue item)
|
|
{
|
|
Throw.IfNull(item, "Cannot add a null item");
|
|
m_dictionary.Add(item);
|
|
base.InsertItem(index, item);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Overridden.
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
protected override void RemoveItem(int index)
|
|
{
|
|
m_dictionary.Remove(GetKeyForItem(base[index]));
|
|
base.RemoveItem(index);
|
|
}
|
|
|
|
/// <summary>
|
|
/// Overridden.
|
|
/// </summary>
|
|
/// <param name="index"></param>
|
|
/// <param name="item"></param>
|
|
protected override void SetItem(int index, TValue item)
|
|
{
|
|
Throw.IfNull(item, "Cannot add a null item");
|
|
TValue oldItem = base[index];
|
|
if (!Equals(oldItem, item))
|
|
{
|
|
m_dictionary.Remove(oldItem);
|
|
m_dictionary.Add(item);
|
|
|
|
base.SetItem(index, item);
|
|
}
|
|
}
|
|
|
|
/// <summary>
|
|
/// Overridden.
|
|
/// </summary>
|
|
protected override void ClearItems()
|
|
{
|
|
if (Count == 0)
|
|
{
|
|
return;
|
|
}
|
|
|
|
m_dictionary.Clear();
|
|
base.ClearItems();
|
|
}
|
|
|
|
/// <summary>
|
|
/// TryGetValue.
|
|
/// </summary>
|
|
public bool TryGetValue(TKey key, out TValue result)
|
|
{
|
|
return m_dictionary.TryGetValue(key, out result);
|
|
}
|
|
|
|
public override int IndexOf(TValue item)
|
|
{
|
|
// Contains is optimized O(1).
|
|
if (!Contains(item))
|
|
{
|
|
return -1;
|
|
}
|
|
|
|
return base.IndexOf(item);
|
|
}
|
|
|
|
#endregion
|
|
|
|
#region Nested
|
|
|
|
private class KeyedCollection : KeyedCollection<TKey, TValue>
|
|
{
|
|
private readonly ObservableKeyedList<TKey, TValue> m_owner;
|
|
|
|
public KeyedCollection(ObservableKeyedList<TKey, TValue> owner)
|
|
{
|
|
m_owner = owner;
|
|
}
|
|
|
|
public KeyedCollection(ObservableKeyedList<TKey, TValue> owner, IEqualityComparer<TKey> comparer)
|
|
: base(comparer)
|
|
{
|
|
m_owner = owner;
|
|
}
|
|
|
|
protected override TKey GetKeyForItem(TValue value)
|
|
{
|
|
return m_owner.GetKeyForItem(value);
|
|
}
|
|
}
|
|
|
|
#endregion
|
|
}
|
|
}
|