Collection with events

NET 4 and WPF brings us the new ObservableCollection that fire events for collection changes and contained objects property changes…but when you don’t need the “MVVM way” and bindings…it’s too much.  As it is contained in the system.dll, we can continue to use actions and event from it.

With ILSpy, I extract the code from this class to make a NotifyCollection just for the use of the items collection events. It can be used in any window service or class library. The code is below and the file is attached. NotifyCollection. Rename docx to zip.

public class NotifyCollection<T> : Collection<T>, INotifyCollectionChanged
{
[Serializable]
privateclassSimpleMonitor : IDisposable
{
private int _busyCount;
public bool Busy
{
get
{
return this._busyCount > 0;
}
}
public void Enter()
{
this._busyCount++;
}
public void Dispose()
{
this._busyCount–;
}
public SimpleMonitor()
{
}
}
 
private NotifyCollection<T>.SimpleMonitor _monitor = newN otifyCollection<T>.SimpleMonitor();
///<summary>Occurs when an item is added, removed, changed, moved, or the entire list is refreshed.</summary>
[field: NonSerialized]
public virtual event NotifyCollectionChangedEventHandler CollectionChanged;
 
///<summary>Initializes a new instance of the <see cref=”T:System.Collections.ObjectModel.ObservableCollection`1″ /> class.</summary>
public NotifyCollection()
{
}
 
///<summary>Initializes a new instance of the <see cref=”T:System.Collections.ObjectModel.ObservableCollection`1″ /> class that contains elements copied from the specified list.</summary>
///<param name=”list”>The list from which the elements are copied.</param>
///<exception cref=”T:System.ArgumentNullException”>The <paramref name=”list” /> parameter cannot be null.</exception>
public NotifyCollection(List<T> list) : base((list != null) ? new List<T>(list.Count) : list)
{
 this.CopyFrom(list);
}
  
///<summary>Initializes a new instance of the <see cref=”T:System.Collections.ObjectModel.ObservableCollection`1″ /> class that contains elements copied from the specified collection.</summary>
///<param name=”collection”>The collection from which the elements are copied.</param>
///<exception cref=”T:System.ArgumentNullException”>The <paramref name=”collection” /> parameter cannot be null.</exception>
public NotifyCollection(IEnumerable<T> collection)
{
 if (collection == null)
{
 throw new ArgumentNullException(“collection”);
}
 this.CopyFrom(collection);
}
 
 private void CopyFrom(IEnumerable<T> collection)
{
 IList<T> items = base.Items;
if (collection != null && items != null)
{
 using (IEnumerator<T> enumerator = collection.GetEnumerator())
{
 while (enumerator.MoveNext())
{
items.Add(enumerator.Current);
}
}
}
}
 
///<summary>Moves the item at the specified index to a new location in the collection.</summary>
///<param name=”oldIndex”>The zero-based index specifying the location of the item to be moved.</param>
///<param name=”newIndex”>The zero-based index specifying the new location of the item.</param>
public void Move(int oldIndex, int newIndex)
this.MoveItem(oldIndex, newIndex);
}  
///<summary>Removes all items from the collection.</summary>
protected override void ClearItems()
this.CheckReentrancy();
base.ClearItems();
this.OnCollectionReset();
///<summary>Removes the item at the specified index of the collection.</summary>
///<param name=”index”>The zero-based index of the element to remove.</param>
protected override void RemoveItem(int index)
this.CheckReentrancy();
T t =base[index];
base.RemoveItem(index);
this.OnCollectionChanged(NotifyCollectionChangedAction.Remove, t, index);
///<summary>Inserts an item into the collection at the specified index.</summary>
///<param name=”index”>The zero-based index at which <paramref name=”item” /> should be inserted.</param>
///<param name=”item”>The object to insert.</param>
protected override void InsertItem(int index, T item)
this.CheckReentrancy();
base.InsertItem(index, item);
this.OnCollectionChanged(NotifyCollectionChangedAction.Add, item, index);
///<summary>Replaces the element at the specified index.</summary>
///<param name=”index”>The zero-based index of the element to replace.</param>
///<param name=”item”>The new value for the element at the specified index.</param>
protected override void SetItem(int index, T item)
this.CheckReentrancy();
T t =base[index];
base.SetItem(index, item);
this.OnCollectionChanged(NotifyCollectionChangedAction.Replace, t, item, index);
///<summary>Moves the item at the specified index to a new location in the collection.</summary>
///<param name=”oldIndex”>The zero-based index specifying the location of the item to be moved.</param>
///<param name=”newIndex”>The zero-based index specifying the new location of the item.</param>
protected virtual void MoveItem(int oldIndex, int newIndex)
this.CheckReentrancy();
T t =base[oldIndex];
base.RemoveItem(oldIndex);
base.InsertItem(newIndex, t);
this.OnCollectionChanged(NotifyCollectionChangedAction.Move, t, newIndex, oldIndex);
///<summary>Raises the <see cref=”E:System.Collections.ObjectModel.ObservableCollection`1.CollectionChanged” /> event with the provided arguments.</summary>
///<param name=”e”>Arguments of the event being raised.</param>
protected virtual void OnCollectionChanged(NotifyCollectionChangedEventArgs e)
if (this.CollectionChanged != null)
using (this.BlockReentrancy())
this.CollectionChanged(this, e);
}
}
///<summary>Disallows reentrant attempts to change this collection.</summary>
///<returns>An <see cref=”T:System.IDisposable” /> object that can be used to dispose of the object.</returns>
protected IDisposable BlockReentrancy()
this._monitor.Enter();
return this._monitor;
///<summary>Checks for reentrant attempts to change this collection.</summary>
///<exception cref=”T:System.InvalidOperationException”>If there was a call to <see cref=”M:System.Collections.ObjectModel.ObservableCollection`1.BlockReentrancy” /> of which the <see cref=”T:System.IDisposable” /> return value has not yet been disposed of. Typically, this means when there are additional attempts to change this collection during a <see cref=”E:System.Collections.ObjectModel.ObservableCollection`1.CollectionChanged” /> event. However, it depends on when derived classes choose to call <see cref=”M:System.Collections.ObjectModel.ObservableCollection`1.BlockReentrancy” />.</exception>
protected void CheckReentrancy()
if (this._monitor.Busy && this.CollectionChanged != null && this.CollectionChanged.GetInvocationList().Length > 1)
throw new InvalidOperationException(“ObservableCollectionReentrancyNotAllowed”);
}
private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index)
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index));
private void OnCollectionChanged(NotifyCollectionChangedAction action, object item, int index, int oldIndex)
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, item, index, oldIndex));
private void OnCollectionChanged(NotifyCollectionChangedAction action, object oldItem, object newItem, int index)
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(action, newItem, oldItem, index));
private void OnCollectionReset()
this.OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Reset));
}
}

Leave a comment