Extended to IObservableCollection interface with an ItemsCleared event so subscribers observing the collection only to trigger 'Changed' events (versus subscribers observing the collection to wire/unwire themselves from the collection's items) can make use of the collection

git-svn-id: file:///srv/devel/repo-conversion/nusu@182 d2e56fa2-650e-0410-a79f-9358c0239efd
This commit is contained in:
Markus Ewald 2009-10-12 19:19:58 +00:00
parent d5293d8cb9
commit 655ae7ab10
5 changed files with 54 additions and 38 deletions

View File

@ -42,6 +42,9 @@ namespace Nuclex.Support.Collections {
/// </remarks>
event EventHandler Clearing;
/// <summary>Raised when the collection has been cleared of its items</summary>
event EventHandler Cleared;
}
} // namespace Nuclex.Support.Collections

View File

@ -42,6 +42,11 @@ namespace Nuclex.Support.Collections {
/// <param name="arguments">Not used</param>
void Clearing(object sender, EventArgs arguments);
/// <summary>Called when the collection has been cleared of its contents</summary>
/// <param name="sender">Collection that was cleared of its contents</param>
/// <param name="arguments">Not used</param>
void Cleared(object sender, EventArgs arguments);
/// <summary>Called when an item is added to the collection</summary>
/// <param name="sender">Collection to which an item is being added</param>
/// <param name="arguments">Contains the item that is being added</param>
@ -64,7 +69,10 @@ namespace Nuclex.Support.Collections {
this.mockedSubscriber = this.mockery.NewMock<IObservableCollectionSubscriber>();
this.observedCollection = new ObservableCollection<int>();
this.observedCollection.Clearing += new EventHandler(this.mockedSubscriber.Clearing);
this.observedCollection.Clearing +=
new EventHandler(this.mockedSubscriber.Clearing);
this.observedCollection.Cleared +=
new EventHandler(this.mockedSubscriber.Cleared);
this.observedCollection.ItemAdded +=
new EventHandler<ItemEventArgs<int>>(
this.mockedSubscriber.ItemAdded
@ -78,9 +86,8 @@ namespace Nuclex.Support.Collections {
/// <summary>Tests whether the Clearing event is fired</summary>
[Test]
public void TestClearingEvent() {
Expect.Once.On(this.mockedSubscriber).
Method("Clearing");
Expect.Once.On(this.mockedSubscriber).Method("Clearing").WithAnyArguments();
Expect.Once.On(this.mockedSubscriber).Method("Cleared").WithAnyArguments();
this.observedCollection.Clear();
this.mockery.VerifyAllExpectationsHaveBeenMet();
@ -89,9 +96,7 @@ namespace Nuclex.Support.Collections {
/// <summary>Tests whether the ItemAdded event is fired</summary>
[Test]
public void TestItemAddedEvent() {
Expect.Once.On(this.mockedSubscriber).
Method("ItemAdded").
WithAnyArguments();
Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
this.observedCollection.Add(123);
@ -101,15 +106,11 @@ namespace Nuclex.Support.Collections {
/// <summary>Tests whether the ItemRemoved event is fired</summary>
[Test]
public void TestItemRemovedEvent() {
Expect.Once.On(this.mockedSubscriber).
Method("ItemAdded").
WithAnyArguments();
Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
this.observedCollection.Add(123);
Expect.Once.On(this.mockedSubscriber).
Method("ItemRemoved").
WithAnyArguments();
Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments();
this.observedCollection.Remove(123);
@ -119,28 +120,20 @@ namespace Nuclex.Support.Collections {
/// <summary>Tests whether items in the collection can be replaced</summary>
[Test]
public void TestItemReplacement() {
Expect.Exactly(3).On(this.mockedSubscriber).
Method("ItemAdded").
WithAnyArguments();
Expect.Exactly(3).On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
this.observedCollection.Add(1);
this.observedCollection.Add(2);
this.observedCollection.Add(3);
Expect.Once.On(this.mockedSubscriber).
Method("ItemRemoved").
WithAnyArguments();
Expect.Once.On(this.mockedSubscriber).
Method("ItemAdded").
WithAnyArguments();
Expect.Once.On(this.mockedSubscriber).Method("ItemRemoved").WithAnyArguments();
Expect.Once.On(this.mockedSubscriber).Method("ItemAdded").WithAnyArguments();
// Replace the middle item with something else
this.observedCollection[1] = 4;
Assert.AreEqual(
1,
this.observedCollection.IndexOf(4)
1, this.observedCollection.IndexOf(4)
);
this.mockery.VerifyAllExpectationsHaveBeenMet();
@ -152,11 +145,8 @@ namespace Nuclex.Support.Collections {
int[] integers = new int[] { 12, 34, 56, 78 };
ObservableCollection<int> testCollection = new ObservableCollection<int>(integers);
CollectionAssert.AreEqual(
integers,
testCollection
);
CollectionAssert.AreEqual(integers, testCollection);
}
/// <summary>Mock object factory</summary>

View File

@ -39,6 +39,8 @@ namespace Nuclex.Support.Collections {
/// to process the clearing of the entire collection as a special operation.
/// </remarks>
public event EventHandler Clearing;
/// <summary>Raised when the collection has been cleared</summary>
public event EventHandler Cleared;
/// <summary>
/// Initializes a new instance of the ObservableCollection class that is empty.
@ -58,8 +60,8 @@ namespace Nuclex.Support.Collections {
/// <summary>Removes all elements from the Collection</summary>
protected override void ClearItems() {
OnClearing();
base.ClearItems();
OnCleared();
}
/// <summary>
@ -71,7 +73,6 @@ namespace Nuclex.Support.Collections {
/// <param name="item">The zero-based index at which item should be inserted</param>
protected override void InsertItem(int index, ItemType item) {
base.InsertItem(index, item);
OnAdded(item);
}
@ -81,9 +82,7 @@ namespace Nuclex.Support.Collections {
/// <param name="index">The zero-based index of the element to remove</param>
protected override void RemoveItem(int index) {
ItemType item = base[index];
base.RemoveItem(index);
OnRemoved(item);
}
@ -95,9 +94,7 @@ namespace Nuclex.Support.Collections {
/// <param name="item">The zero-based index of the element to replace</param>
protected override void SetItem(int index, ItemType item) {
ItemType oldItem = base[index];
base.SetItem(index, item);
OnRemoved(oldItem);
OnAdded(item);
}
@ -122,6 +119,12 @@ namespace Nuclex.Support.Collections {
Clearing(this, EventArgs.Empty);
}
/// <summary>Fires the 'Cleared' event</summary>
protected virtual void OnCleared() {
if(Cleared != null)
Cleared(this, EventArgs.Empty);
}
}
} // namespace Nuclex.Support.Collections

View File

@ -45,6 +45,11 @@ namespace Nuclex.Support.Collections {
/// <param name="arguments">Not used</param>
void Clearing(object sender, EventArgs arguments);
/// <summary>Called when the dictionary has been clear of its contents</summary>
/// <param name="sender">Dictionary that was cleared of its contents</param>
/// <param name="arguments">Not used</param>
void Cleared(object sender, EventArgs arguments);
/// <summary>Called when an item is added to the dictionary</summary>
/// <param name="sender">Dictionary to which an item is being added</param>
/// <param name="arguments">Contains the item that is being added</param>
@ -72,7 +77,10 @@ namespace Nuclex.Support.Collections {
this.observedDictionary.Add(3, "three");
this.observedDictionary.Add(42, "forty-two");
this.observedDictionary.Clearing += new EventHandler(this.mockedSubscriber.Clearing);
this.observedDictionary.Clearing +=
new EventHandler(this.mockedSubscriber.Clearing);
this.observedDictionary.Cleared +=
new EventHandler(this.mockedSubscriber.Cleared);
this.observedDictionary.ItemAdded +=
new EventHandler<ItemEventArgs<KeyValuePair<int, string>>>(
this.mockedSubscriber.ItemAdded
@ -293,6 +301,7 @@ namespace Nuclex.Support.Collections {
[Test]
public void TestClearViaIDictionary() {
Expect.Once.On(this.mockedSubscriber).Method("Clearing").WithAnyArguments();
Expect.Once.On(this.mockedSubscriber).Method("Cleared").WithAnyArguments();
(this.observedDictionary as IDictionary).Clear();
this.mockery.VerifyAllExpectationsHaveBeenMet();
@ -424,6 +433,7 @@ namespace Nuclex.Support.Collections {
[Test]
public void TestClearViaGenericICollection() {
Expect.Once.On(this.mockedSubscriber).Method("Clearing").WithAnyArguments();
Expect.Once.On(this.mockedSubscriber).Method("Cleared").WithAnyArguments();
(this.observedDictionary as ICollection<KeyValuePair<int, string>>).Clear();
this.mockery.VerifyAllExpectationsHaveBeenMet();

View File

@ -32,7 +32,7 @@ namespace Nuclex.Support.Collections {
[Serializable]
public class ObservableDictionary<KeyType, ValueType> :
#if !NO_SERIALIZATION
ISerializable,
ISerializable,
IDeserializationCallback,
#endif
IDictionary<KeyType, ValueType>,
@ -76,6 +76,8 @@ namespace Nuclex.Support.Collections {
public event EventHandler<ItemEventArgs<KeyValuePair<KeyType, ValueType>>> ItemRemoved;
/// <summary>Raised when the dictionary is about to be cleared</summary>
public event EventHandler Clearing;
/// <summary>Raised when the dictionary has been cleared</summary>
public event EventHandler Cleared;
/// <summary>Initializes a new observable dictionary</summary>
public ObservableDictionary() : this(new Dictionary<KeyType, ValueType>()) { }
@ -220,6 +222,7 @@ namespace Nuclex.Support.Collections {
public void Clear() {
OnClearing();
this.typedDictionary.Clear();
OnCleared();
}
/// <summary>Fires the 'ItemAdded' event</summary>
@ -242,6 +245,12 @@ namespace Nuclex.Support.Collections {
Clearing(this, EventArgs.Empty);
}
/// <summary>Fires the 'Cleared' event</summary>
protected virtual void OnCleared() {
if(Cleared != null)
Cleared(this, EventArgs.Empty);
}
#region IEnumerable implementation
/// <summary>Returns a new object enumerator for the Dictionary</summary>
@ -337,6 +346,7 @@ namespace Nuclex.Support.Collections {
void ICollection<KeyValuePair<KeyType, ValueType>>.Clear() {
OnClearing();
this.typedDictionary.Clear();
OnCleared();
}
/// <summary>Removes all items from the Dictionary</summary>