Observing changes to a List<T> by adding events
- 📅
- 📝 580 words
- 🕙 3 minutes
- 📦 .NET
- 🏷️ C#
- 💬 8 responses
In an attempt to get more C# and .NET content up I’m putting up some snippets I’ve put together in response to questions on some C# user support groups. Many of them are not particularly advanced but they are quite useful.
GitHub has the latest version of
ObservableList<T>
This sample shows how to observe events on an generic IList<T>
. It does this by way of implementing the IList<T>
interface over the top of something that already supports IList<T>
to do the actual work and highlights how useful publishing the interface, IList<T>
, separate from the actual concrete class List<T>
can be for reuse.
using System;
using System.Collections;
using System.Collections.Generic;
public class ObservableList<T> : IList<T> {
private IList<T> internalList;
public class ListChangedEventArgs : EventArgs {
public int index;
public T item;
public ListChangedEventArgs(int index, T item) {
this.index = index;
this.item = item;
}
}
public delegate void ListChangedEventHandler(object source, ListChangedEventArgs e);
public delegate void ListClearedEventHandler(object source, EventArgs e);
public event ListChangedEventHandler ListChanged;
public event ListClearedEventHandler ListCleared;
public ObservableList() {
internalList = new List<T>();
}
public ObservableList(IList<T> list) {
internalList = list;
}
public ObservableList(IEnumerable<T> collection) {
internalList = new List<T>(collection);
}
protected virtual void OnListChanged(ListChangedEventArgs e) {
if (ListChanged != null)
ListChanged(this, e);
}
protected virtual void OnListCleared(EventArgs e) {
if (ListCleared != null)
ListCleared(this, e);
}
public int IndexOf(T item) {
return internalList.IndexOf(item);
}
public void Insert(int index, T item) {
internalList.Insert(index, item);
OnListChanged(new ListChangedEventArgs(index, item));
}
public void RemoveAt(int index) {
T item = internalList[index];
internalList.Remove(item);
OnListChanged(new ListChangedEventArgs(index, item));
}
public T this[int index] {
get { return internalList[index]; }
set {
internalList[index] = value;
OnListChanged(new ListChangedEventArgs(index, value));
}
}
public void Add(T item) {
internalList.Add(item);
OnListChanged(new ListChangedEventArgs(internalList.IndexOf(item), item));
}
public void Clear() {
internalList.Clear();
OnListCleared(new EventArgs());
}
public bool Contains(T item) {
return internalList.Contains(item);
}
public void CopyTo(T[] array, int arrayIndex) {
internalList.CopyTo(array, arrayIndex);
}
public int Count {
get { return internalList.Count; }
}
public bool IsReadOnly {
get { return internalList.IsReadOnly; }
}
public bool Remove(T item) {
lock(this) {
int index = internalList.IndexOf(item);
if (internalList.Remove(item)) {
OnListChanged(new ListChangedEventArgs(index, item));
return true;
}
else
return false;
}
}
public IEnumerator<T> GetEnumerator() {
return internalList.GetEnumerator();
}
IEnumerator IEnumerable.GetEnumerator() {
return ((IEnumerable) internalList).GetEnumerator();
}
}
[)amien
8 responses to Observing changes to a List<T> by adding events
Great post. Thank you for this. One note that took me several hours to realize. The RemoveAt(int index) method is broken. Passing any index, it will remove the item starting at the beginning index of 0. I remember there being a bug in .Net 2.0 regarding this and I think they fixed in later releases but since Unity only supports 2.0, felt it was worthwhile to mention. If you find your list removing the wrong items when you call RemoveAt(), try replacing the RemoveAt method with the following:
Thanks again. Works great!
Nice one Damien, your CopyTo implementation should be internalList.CopyTo though, other wise you will get the nice StackOverflow exception.
Good stuff guys.
Hey Damien, In case you are looking for a good example of the Decorator pattern, you can check out the article I wrote.
Damien, This is good stuff, as always!
Oh, and I even found you a link to a pretty decent high-level explaination of the Decorator Pattern. Gotta’ love Wikipedia!
BindingList does indeed have events but it’s primary purpose is for data binding and the events and sorting are exposed as part of that.
I was going to put that it was an illustration of the decorator pattern but couldn’t find a decent decorator reference online to link to and didn’t feel like trying to cover that myself.
I smell a Decorator pattern :)
How does this compare to using
BindingList<T>
? It already had list changed events built in.