Skip to content

Observing changes to a List by adding events  

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];
    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) {
    OnListChanged(new ListChangedEventArgs(internalList.IndexOf(item), item));

  public void 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;
        return false;

  public IEnumerator<T> GetEnumerator() {
    return internalList.GetEnumerator();

  IEnumerator IEnumerable.GetEnumerator() {
    return ((IEnumerable) internalList).GetEnumerator();


8 responses  

  1. How does this compare to using BindingList<T>? It already had list changed events built in.

    Will Gant – June 14th, 2006
  2. I smell a Decorator pattern :)

    SteveJune 15th, 2006
  3. 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.


    Damien GuardJune 15th, 2006
  4. 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!

    Steve HarmanJune 15th, 2006
  5. Hey Damien, In case you are looking for a good example of the Decorator pattern, you can check out the article I wrote.

    Jean-Paul S. BoodhooJune 16th, 2006
  6. Good stuff guys.


    Damien GuardAugust 2nd, 2007
  7. Nice one Damien, your CopyTo implementation should be internalList.CopyTo though, other wise you will get the nice StackOverflow exception.

    Mo Samara – February 19th, 2011
  8. 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:

    public void RemoveAt(int index) {
    	T item = internalList[index];
    	OnListChanged(new ListChangedEventArgs(index, item));

    Thanks again. Works great!

    Sailor – July 11th, 2014

Respond to this