Observing changes to a List<T> by adding events

June 14th 2006 • .NET (, , , ) • 2,886 views • 6 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 enquiries on some C# user support groups. Many of them are not particularly advanced but they are quite useful.

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));
  }

  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) {
    CopyTo(array, arrayIndex);
  }

  public int Count {
    get { return internalList.Count; }
  }

  public bool IsReadOnly {
    get { return 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

Related content

6 responses  

  1. Will Gant on June 14th, 2006

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

  2. Steve on June 15th, 2006

    I smell a Decorator pattern :)

  3. Damien Guard on June 15th, 2006

    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.

    [)amien

  4. Steve Harman on June 15th, 2006

    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!

  5. Jean-Paul S. Boodhoo on June 16th, 2006

    Hey Damien, In case you are looking for a good example of the Decorator pattern, you can check out the article I wrote.

  6. Damien Guard on August 2nd, 2007

    Good stuff guys.

    [)amien

Leave your response

  1. (kept private)