#region Apache License 2.0
/*
Nuclex .NET Framework
Copyright (C) 2002-2024 Markus Ewald / Nuclex Development Labs
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
#endregion // Apache License 2.0
using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
#if !NO_SPECIALIZED_COLLECTIONS
using System.Collections.Specialized;
#endif
namespace Nuclex.Support.Collections {
/// Collection which fires events when items are added or removed
/// Type of items the collection manages
public class ObservableCollection :
ICollection,
ICollection,
#if !NO_SPECIALIZED_COLLECTIONS
INotifyCollectionChanged,
#endif
IObservableCollection {
/// Raised when an item has been added to the collection
public event EventHandler> ItemAdded;
/// Raised when an item is removed from the collection
public event EventHandler> ItemRemoved;
/// Raised when an item is replaced in the collection
public event EventHandler> ItemReplaced {
add { }
remove { }
}
/// Raised when the collection is about to be cleared
///
/// This could be covered by calling ItemRemoved for each item currently
/// contained in the collection, but it is often simpler and more efficient
/// to process the clearing of the entire collection as a special operation.
///
public event EventHandler Clearing;
/// Raised when the collection has been cleared
public event EventHandler Cleared;
#if !NO_SPECIALIZED_COLLECTIONS
/// Called when the collection has changed
public event NotifyCollectionChangedEventHandler CollectionChanged;
#endif
/// Initializes a new ObservableCollection with no items
public ObservableCollection() : this(new Collection()) { }
///
/// Initializes a new ObservableCollection as a wrapper for an existing collection
///
/// Collection that will be wrapped
/// List is null
public ObservableCollection(ICollection collection) {
this.typedCollection = collection;
this.objectCollection = (collection as ICollection);
}
/// Removes all elements from the Collection
public void Clear() {
OnClearing();
this.typedCollection.Clear();
OnCleared();
}
/// Adds an item to the collection
/// Collection an item will be added to
public void Add(TItem item) {
this.typedCollection.Add(item);
OnAdded(item);
}
/// 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
///
public void CopyTo(TItem[] array, int arrayIndex) {
this.typedCollection.CopyTo(array, arrayIndex);
}
/// The total number of items currently in the collection
public int Count {
get { return this.typedCollection.Count; }
}
/// 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);
}
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
/// Item that has been added to the collection
protected virtual void OnAdded(TItem item) {
if(ItemAdded != null) {
ItemAdded(this, new ItemEventArgs(item));
}
#if !NO_SPECIALIZED_COLLECTIONS
if(CollectionChanged != null) {
CollectionChanged(
this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Add, item)
);
}
#endif
}
/// Fires the 'ItemRemoved' event
/// Item that has been removed from the collection
protected virtual void OnRemoved(TItem item) {
if(ItemRemoved != null) {
ItemRemoved(this, new ItemEventArgs(item));
}
#if !NO_SPECIALIZED_COLLECTIONS
if(CollectionChanged != null) {
CollectionChanged(
this,
new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, item)
);
}
#endif
}
/// Fires the 'Clearing' event
protected virtual void OnClearing() {
if(Clearing != null) {
Clearing(this, EventArgs.Empty);
}
}
/// Fires the 'Cleared' event
protected virtual void OnCleared() {
if(Cleared != null) {
Cleared(this, EventArgs.Empty);
}
#if !NO_SPECIALIZED_COLLECTIONS
if(CollectionChanged != null) {
CollectionChanged(this, Constants.NotifyCollectionResetEventArgs);
}
#endif
}
#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
/// 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