#region CPL License /* Nuclex Framework Copyright (C) 2002-2009 Nuclex Development Labs This library is free software; you can redistribute it and/or modify it under the terms of the IBM Common Public License as published by the IBM Corporation; either version 1.0 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the IBM Common Public License for more details. You should have received a copy of the IBM Common Public License along with this library */ #endregion using System; using System.Collections.Generic; using System.Collections; using System.Collections.ObjectModel; using System.Runtime.Serialization; namespace Nuclex.Support.Collections { /// A dictionary that sneds out change notifications /// Type of the keys used in the dictionary /// Type of the values used in the dictionary [Serializable] public class ObservableDictionary : #if !COMPACTFRAMEWORK ISerializable, IDeserializationCallback, #endif IDictionary, IDictionary { #if !COMPACTFRAMEWORK #region class SerializedDictionary /// /// Dictionary wrapped used to reconstruct a serialized read only dictionary /// private class SerializedDictionary : Dictionary { /// /// Initializes a new instance of the System.WeakReference class, using deserialized /// data from the specified serialization and stream objects. /// /// /// An object that holds all the data needed to serialize or deserialize the /// current System.WeakReference object. /// /// /// (Reserved) Describes the source and destination of the serialized stream /// specified by info. /// /// /// The info parameter is null. /// public SerializedDictionary(SerializationInfo info, StreamingContext context) : base(info, context) { } } #endregion // class SerializeDictionary #endif // !COMPACTFRAMEWORK /// Raised when an item has been added to the dictionary public event EventHandler>> ItemAdded; /// Raised when an item is removed from the dictionary public event EventHandler>> ItemRemoved; /// Raised when the dictionary is about to be cleared public event EventHandler Clearing; /// Initializes a new observable dictionary public ObservableDictionary() : this(new Dictionary()) { } /// Initializes a new observable Dictionary wrapper /// Dictionary that will be wrapped public ObservableDictionary(IDictionary dictionary) { this.typedDictionary = dictionary; this.objectDictionary = (this.typedDictionary as IDictionary); } #if !COMPACTFRAMEWORK /// /// Initializes a new instance of the System.WeakReference class, using deserialized /// data from the specified serialization and stream objects. /// /// /// An object that holds all the data needed to serialize or deserialize the /// current System.WeakReference object. /// /// /// (Reserved) Describes the source and destination of the serialized stream /// specified by info. /// /// /// The info parameter is null. /// protected ObservableDictionary(SerializationInfo info, StreamingContext context) : this(new SerializedDictionary(info, context)) { } #endif // !COMPACTFRAMEWORK /// Whether the directory is write-protected public bool IsReadOnly { get { return this.typedDictionary.IsReadOnly; } } /// /// Determines whether the specified KeyValuePair is contained in the Dictionary /// /// KeyValuePair that will be checked for /// True if the provided KeyValuePair was contained in the Dictionary public bool Contains(KeyValuePair item) { return this.typedDictionary.Contains(item); } /// Determines whether the Dictionary contains the specified key /// Key that will be checked for /// /// True if an entry with the specified key was contained in the Dictionary /// public bool ContainsKey(KeyType key) { return this.typedDictionary.ContainsKey(key); } /// Copies the contents of the Dictionary into an array /// Array the Dictionary will be copied into /// /// Starting index at which to begin filling the destination array /// public void CopyTo(KeyValuePair[] array, int arrayIndex) { this.typedDictionary.CopyTo(array, arrayIndex); } /// Number of elements contained in the Dictionary public int Count { get { return this.typedDictionary.Count; } } /// Creates a new enumerator for the Dictionary /// The new Dictionary enumerator public IEnumerator> GetEnumerator() { return this.typedDictionary.GetEnumerator(); } /// Collection of all keys contained in the Dictionary public ICollection Keys { get { return this.typedDictionary.Keys; } } /// Collection of all values contained in the Dictionary public ICollection Values { get { return this.typedDictionary.Values; } } /// /// Attempts to retrieve the item with the specified key from the Dictionary /// /// Key of the item to attempt to retrieve /// /// Output parameter that will receive the key upon successful completion /// /// /// True if the item was found and has been placed in the output parameter /// public bool TryGetValue(KeyType key, out ValueType value) { return this.typedDictionary.TryGetValue(key, out value); } /// Accesses an item in the Dictionary by its key /// Key of the item that will be accessed public ValueType this[KeyType key] { get { return this.typedDictionary[key]; } set { bool removed; ValueType oldValue; removed = this.typedDictionary.TryGetValue(key, out oldValue); this.typedDictionary[key] = value; if(removed) { OnRemoved(new KeyValuePair(key, oldValue)); } OnAdded(new KeyValuePair(key, value)); } } /// Inserts an item into the Dictionary /// Key under which to add the new item /// Item that will be added to the Dictionary public void Add(KeyType key, ValueType value) { this.typedDictionary.Add(key, value); OnAdded(new KeyValuePair(key, value)); } /// Removes the item with the specified key from the Dictionary /// Key of the elementes that will be removed /// True if an item with the specified key was found and removed public bool Remove(KeyType key) { ValueType oldValue; this.typedDictionary.TryGetValue(key, out oldValue); bool removed = this.typedDictionary.Remove(key); if(removed) { OnRemoved(new KeyValuePair(key, oldValue)); } return removed; } /// Removes all items from the Dictionary public void Clear() { OnClearing(); this.typedDictionary.Clear(); } /// Fires the 'ItemAdded' event /// Item that has been added to the collection protected virtual void OnAdded(KeyValuePair item) { if(ItemAdded != null) ItemAdded(this, new ItemEventArgs>(item)); } /// Fires the 'ItemRemoved' event /// Item that has been removed from the collection protected virtual void OnRemoved(KeyValuePair item) { if(ItemRemoved != null) ItemRemoved(this, new ItemEventArgs>(item)); } /// Fires the 'Clearing' event protected virtual void OnClearing() { if(Clearing != null) Clearing(this, EventArgs.Empty); } #region IEnumerable implementation /// Returns a new object enumerator for the Dictionary /// The new object enumerator System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator() { return (this.typedDictionary as IEnumerable).GetEnumerator(); } #endregion #region IDictionary implementation /// Adds an item into the Dictionary /// Key under which the item will be added /// Item that will be added void IDictionary.Add(object key, object value) { this.objectDictionary.Add(key, value); OnAdded(new KeyValuePair((KeyType)key, (ValueType)value)); } /// Determines whether the specified key exists in the Dictionary /// Key that will be checked for /// True if an item with the specified key exists in the Dictionary bool IDictionary.Contains(object key) { return this.objectDictionary.Contains(key); } /// Returns a new entry enumerator for the dictionary /// The new entry enumerator IDictionaryEnumerator IDictionary.GetEnumerator() { return this.objectDictionary.GetEnumerator(); } /// Whether the size of the Dictionary is fixed bool IDictionary.IsFixedSize { get { return this.objectDictionary.IsFixedSize; } } /// Returns a collection of all keys in the Dictionary ICollection IDictionary.Keys { get { return this.objectDictionary.Keys; } } /// Returns a collection of all values stored in the Dictionary ICollection IDictionary.Values { get { return this.objectDictionary.Values; } } /// Removes an item from the Dictionary /// Key of the item that will be removed void IDictionary.Remove(object key) { ValueType value; bool removed = this.typedDictionary.TryGetValue((KeyType)key, out value); this.objectDictionary.Remove(key); if(removed) { OnRemoved(new KeyValuePair((KeyType)key, (ValueType)value)); } } /// Accesses an item in the Dictionary by its key /// Key of the item that will be accessed /// The item with the specified key object IDictionary.this[object key] { get { return this.objectDictionary[key]; } set { bool removed; ValueType oldValue; removed = this.typedDictionary.TryGetValue((KeyType)key, out oldValue); this.objectDictionary[key] = value; if(removed) { OnRemoved(new KeyValuePair((KeyType)key, oldValue)); } OnAdded(new KeyValuePair((KeyType)key, (ValueType)value)); } } #endregion #region ICollection<> implementation /// Inserts an already prepared element into the Dictionary /// Prepared element that will be added to the Dictionary void ICollection>.Add( KeyValuePair item ) { this.typedDictionary.Add(item); OnAdded(item); } /// Removes all items from the Dictionary void ICollection>.Clear() { OnClearing(); this.typedDictionary.Clear(); } /// Removes all items from the Dictionary /// Item that will be removed from the Dictionary bool ICollection>.Remove( KeyValuePair itemToRemove ) { bool removed = this.typedDictionary.Remove(itemToRemove); if(removed) { OnRemoved(itemToRemove); } return removed; } #endregion #region ICollection implementation /// Copies the contents of the Dictionary into an array /// Array the Dictionary contents will be copied into /// /// Starting index at which to begin filling the destination array /// void ICollection.CopyTo(Array array, int index) { this.objectDictionary.CopyTo(array, index); } /// Whether the Dictionary is synchronized for multi-threaded usage bool ICollection.IsSynchronized { get { return this.objectDictionary.IsSynchronized; } } /// Synchronization root on which the Dictionary locks object ICollection.SyncRoot { get { return this.objectDictionary.SyncRoot; } } #endregion #if !COMPACTFRAMEWORK #region ISerializable implementation /// Serializes the Dictionary /// /// Provides the container into which the Dictionary will serialize itself /// /// /// Contextual informations about the serialization environment /// void ISerializable.GetObjectData(SerializationInfo info, StreamingContext context) { (this.typedDictionary as ISerializable).GetObjectData(info, context); } /// Called after all objects have been successfully deserialized /// Nicht unterstützt void IDeserializationCallback.OnDeserialization(object sender) { (this.typedDictionary as IDeserializationCallback).OnDeserialization(sender); } #endregion #endif //!COMPACTFRAMEWORK /// The wrapped Dictionary under its type-safe interface private IDictionary typedDictionary; /// The wrapped Dictionary under its object interface private IDictionary objectDictionary; } } // namespace Nuclex.Support.Collections