diff --git a/Source/Collections/ObservableCollection.Test.cs b/Source/Collections/ObservableCollection.Test.cs index 41aa18b..ec5095e 100644 --- a/Source/Collections/ObservableCollection.Test.cs +++ b/Source/Collections/ObservableCollection.Test.cs @@ -117,30 +117,6 @@ namespace Nuclex.Support.Collections { this.mockery.VerifyAllExpectationsHaveBeenMet(); } - /// Tests whether items in the collection can be replaced - [Test] - public void TestItemReplacement() { - this.mockedSubscriber.Expects.Exactly(3).Method( - m => m.ItemAdded(null, null) - ).WithAnyArguments(); - - this.observedCollection.Add(1); - this.observedCollection.Add(2); - this.observedCollection.Add(3); - - this.mockedSubscriber.Expects.One.Method(m => m.ItemRemoved(null, null)).WithAnyArguments(); - this.mockedSubscriber.Expects.One.Method(m => m.ItemAdded(null, null)).WithAnyArguments(); - - // Replace the middle item with something else - this.observedCollection[1] = 4; - - Assert.AreEqual( - 1, this.observedCollection.IndexOf(4) - ); - - this.mockery.VerifyAllExpectationsHaveBeenMet(); - } - /// Tests whether a the list constructor is working [Test] public void TestListConstructor() { diff --git a/Source/Collections/ObservableCollection.cs b/Source/Collections/ObservableCollection.cs index 89f5fc1..0ae0342 100644 --- a/Source/Collections/ObservableCollection.cs +++ b/Source/Collections/ObservableCollection.cs @@ -19,6 +19,7 @@ License along with this library #endregion using System; +using System.Collections; using System.Collections.Generic; using System.Collections.ObjectModel; #if !NO_SPECIALIZED_COLLECTIONS @@ -30,7 +31,8 @@ namespace Nuclex.Support.Collections { /// Collection which fires events when items are added or removed /// Type of items the collection manages public class ObservableCollection : - Collection, + ICollection, + ICollection, #if !NO_SPECIALIZED_COLLECTIONS INotifyCollectionChanged, #endif @@ -55,87 +57,98 @@ namespace Nuclex.Support.Collections { public event NotifyCollectionChangedEventHandler CollectionChanged; #endif - /// - /// Initializes a new instance of the ObservableCollection class that is empty. - /// - public ObservableCollection() : base() { } + /// Initializes a new ObservableCollection with no items + public ObservableCollection() : this(new Collection()) {} /// - /// Initializes a new instance of the ObservableCollection class as a wrapper - /// for the specified list. + /// Initializes a new ObservableCollection as a wrapper for an existing collection /// - /// The list that is wrapped by the new collection. + /// Collection that will be wrapped /// List is null - public ObservableCollection(IList list) : base(list) { } + public ObservableCollection(ICollection collection) { + this.typedCollection = collection; + this.objectCollection = (collection as ICollection); + } /// Removes all elements from the Collection - protected override void ClearItems() { + public void Clear() { OnClearing(); - base.ClearItems(); + this.typedCollection.Clear(); OnCleared(); #if !NO_SPECIALIZED_COLLECTIONS - OnCollectionChanged(NotifyCollectionChangedAction.Reset, default(TItem), -1); + if(CollectionChanged != null) { + CollectionChanged(this, CollectionResetEventArgs); + } #endif } + /// Adds an item to the collection + /// Collection an item will be added to + public void Add(TItem item) { + this.typedCollection.Add(item); + OnAdded(item); #if !NO_SPECIALIZED_COLLECTIONS - /// Fires the CollectionChanged event - /// Type of change that has occured - /// The item that has been added, removed or replaced - /// Index of the changed item - protected virtual void OnCollectionChanged( - NotifyCollectionChangedAction action, TItem item, int index - ) { if(CollectionChanged != null) { CollectionChanged( - this, new NotifyCollectionChangedEventArgs(action, item, index) - ); + this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item) + ); } - } #endif + } - /// - /// Inserts an element into the ObservableCollection at the specified index - /// - /// - /// The object to insert. The value can be null for reference types. + /// Determines whether the collection contains the specified item + /// Item the collection will be searched for + /// + /// True if the collection contains the specified item, false otherwise + /// + public bool Contains(TItem item) { + return this.typedCollection.Contains(item); + } + + /// Copies the contents of the collection into an array + /// Array the collection's contents will be copied into + /// + /// Index in the array where the collection's first item will be placed /// - /// The zero-based index at which item should be inserted - protected override void InsertItem(int index, TItem item) { - base.InsertItem(index, item); - OnAdded(item); -#if !NO_SPECIALIZED_COLLECTIONS - OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index); -#endif + public void CopyTo(TItem[] array, int arrayIndex) { + this.typedCollection.CopyTo(array, arrayIndex); } - /// - /// Removes the element at the specified index of the ObservableCollection - /// - /// The zero-based index of the element to remove - protected override void RemoveItem(int index) { - TItem item = base[index]; - base.RemoveItem(index); - OnRemoved(item); -#if !NO_SPECIALIZED_COLLECTIONS - OnCollectionChanged(NotifyCollectionChangedAction.Remove, item, index); -#endif + /// The total number of items currently in the collection + public int Count { + get { return this.typedCollection.Count; } } - /// Replaces the element at the specified index - /// - /// The new value for the element at the specified index. The value can be null - /// for reference types - /// - /// The zero-based index of the element to replace - protected override void SetItem(int index, TItem item) { - TItem oldItem = base[index]; - base.SetItem(index, item); - OnRemoved(oldItem); - OnAdded(item); + /// Whether the collection is read-only + public bool IsReadOnly { + get { return this.typedCollection.IsReadOnly; } + } + + /// Removes an item from the collection + /// Item that will be removed from the collection + /// True if the item was found and removed, false otherwise + public bool Remove(TItem item) { + bool wasRemoved = this.typedCollection.Remove(item); + if(wasRemoved) { + OnRemoved(item); #if !NO_SPECIALIZED_COLLECTIONS - OnCollectionChanged(NotifyCollectionChangedAction.Replace, item, index); + if(CollectionChanged != null) { + CollectionChanged( + this, + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item) + ); + } #endif + } + + return wasRemoved; + } + + /// Returns an enumerator for the items in the collection + /// An enumeration for the items in the collection + public IEnumerator GetEnumerator() { + return this.typedCollection.GetEnumerator(); } /// Fires the 'ItemAdded' event @@ -164,6 +177,52 @@ namespace Nuclex.Support.Collections { Cleared(this, EventArgs.Empty); } + #region IEnumerable implementation + + /// Returns an enumerator for the items in the collection + /// An enumeration for the items in the collection + IEnumerator IEnumerable.GetEnumerator() { + return this.objectCollection.GetEnumerator(); + } + + #endregion // IEnumerable implementation + + #region ICollection implementation + + /// Copies the contents of the collection into an array + /// Array the collection's contents will be copied into + /// + /// Index in the array where the collection's first item will be placed + /// + void ICollection.CopyTo(Array array, int arrayIndex) { + this.objectCollection.CopyTo(array, arrayIndex); + } + + /// Whether the collection synchronizes accesses from multiple threads + bool ICollection.IsSynchronized { + get { return this.objectCollection.IsSynchronized; } + } + + /// + /// Synchronization root used to synchronize threads accessing the collection + /// + object ICollection.SyncRoot { + get { return this.objectCollection.SyncRoot; } + } + + #endregion // IEnumerable implementation + +#if !NO_SPECIALIZED_COLLECTIONS + /// Fixed event args used to notify that the collection has reset + private static readonly NotifyCollectionChangedEventArgs CollectionResetEventArgs = + new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); +#endif + + /// The wrapped collection under its type-safe interface + private ICollection typedCollection; + /// The wrapped collection under its object interface + private ICollection objectCollection; + } } // namespace Nuclex.Support.Collections diff --git a/Source/Collections/ObservableList.cs b/Source/Collections/ObservableList.cs index f6ce57c..710c15f 100644 --- a/Source/Collections/ObservableList.cs +++ b/Source/Collections/ObservableList.cs @@ -364,9 +364,9 @@ namespace Nuclex.Support.Collections { new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset); #endif - /// The wrapped List under its type-safe interface + /// The wrapped list under its type-safe interface private IList typedList; - /// The wrapped List under its object interface + /// The wrapped list under its object interface private IList objectList; }