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