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