A common way of providing data for a listbox is the ObservableCollection. It’s easy to bind the collection to a listbox and then add items to it. But where is the AddRange(IEnumerable<T> collection) method? There is none, so all items must be added one by one. Each time an item is added, the collection notifies the listeners of the CollectionChanged property, usually some data bound controls. That means there is a lot of harmless event noise, but it still bothered me. In some cases I suspect that the performance will drop significantly, e.g. when using controls which are expensive to update several hundred times. (Note that the ListBox uses a VirtualizationPanel to maintain performance.)

So I looked up some documentation on MSDN and deceided to implement my very own ObservableList<T>, a List<T> implementing the INotifyCollectionChanged interface. It seems easy enough, just fire the CollectionChanged event whenever some items are added or removed.

This snipped shows how it works. I wrapp the regular AddRange(IEnumerable collection) method and raise the CollectionChanged event. Same procedure for the other methods which add or remove items, including the indexer property. The NotifyCollectionChangedEventArgs specifies what changed. Sometimes I don’t want to raise the event, so I provided the IsNotifying property to switch that on or off.

public class ObservableList <T> : List <T>, INotifyINotifyCollectionChanged

public new void AddRange( IEnumerable <T> collection)

base .AddRange(collection);

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Add, new List <T>(collection));

OnCollectionChanged(e);

protected void OnCollectionChanged( NotifyCollectionChangedEventArgs e)

if (IsNotifying && CollectionChanged != null )

CollectionChanged( this , e);

Now it’s time to hook up my shiny, new ObservableList<T>! That’s when WPF notified me it doesn’t like ranges.

Ranges are not supported

Ranges are not supported

So what happened here? The ListBox to wich the list is data bound is being picky about kind of information I give to the NotifyCollectionChangedEventArgs. Obviously, it doen’t like range updates.

That was kind of disappointing but not as bad as I thought at first. Why is the NotifyCollectionChangedEventArgs class that elaborate in the first place?? I fixed this by raising the event slightly differently when this exception occurs.

protected void OnCollectionChanged( NotifyCollectionChangedEventArgs e)

if (IsNotifying && CollectionChanged != null )

CollectionChanged( this , e);

catch (System. NotSupportedException )

NotifyCollectionChangedEventArgs alternativeEventArgs =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Reset);

OnCollectionChanged(alternativeEventArgs);

So here is the complete code to copy and paste.

public interface IObservableList <T> : IList <T>, INotifyCollectionChanged { }

public class ObservableList <T> : List <T>, IObservableList <T>, INotifyPropertyChanged

#region Constructors

public ObservableList()

IsNotifying = true ;

// As a gimmick, I wanted to bind to the Count property, so I

// use the OnPropertyChanged event from the INotifyPropertyChanged

// interface to notify about Count changes.

CollectionChanged += new NotifyCollectionChangedEventHandler (

delegate ( object sender, NotifyCollectionChangedEventArgs e)

OnPropertyChanged( "Count" );

#endregion

#region Properties

public bool IsNotifying { get ; set ; }

#endregion

#region Adding and removing items

public new void Add(T item)

base .Add(item);

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Add, item);

OnCollectionChanged(e);

public new void AddRange( IEnumerable <T> collection)

base .AddRange(collection);

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Add, new List <T>(collection));

OnCollectionChanged(e);

public new void Clear()

base .Clear();

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Reset);

OnCollectionChanged(e);

public new void Insert( int i, T item)

base .Insert(i, item);

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Add, item);

OnCollectionChanged(e);

public new void InsertRange( int i, IEnumerable <T> collection)

base .InsertRange(i, collection);

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Add, collection);

OnCollectionChanged(e);

public new void Remove(T item)

base .Remove(item);

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Remove, item);

OnCollectionChanged(e);

public new void RemoveAll( Predicate <T> match)

List <T> backup = FindAll(match);

base .RemoveAll(match);

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Remove, backup);

OnCollectionChanged(e);

public new void RemoveAt( int i)

T backup = this [i];

base .RemoveAt(i);

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Remove, backup);

OnCollectionChanged(e);

public new void RemoveRange( int index, int count)

List <T> backup = GetRange(index, count);

base .RemoveRange(index, count);

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Remove, backup);

OnCollectionChanged(e);

public new T this [ int index]

get { return base [index]; }

T oldValue = base [index];

NotifyCollectionChangedEventArgs e =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Replace, value , oldValue);

OnCollectionChanged(e);

#endregion

#region INotifyCollectionChanged Members

public event NotifyCollectionChangedEventHandler CollectionChanged;

protected void OnCollectionChanged( NotifyCollectionChangedEventArgs e)

if (IsNotifying && CollectionChanged != null )

CollectionChanged( this , e);

catch (System. NotSupportedException )

NotifyCollectionChangedEventArgs alternativeEventArgs =

new NotifyCollectionChangedEventArgs ( NotifyCollectionChangedAction .Reset);

OnCollectionChanged(alternativeEventArgs);

#endregion

#region INotifyPropertyChanged Members

public event PropertyChangedEventHandler PropertyChanged;

protected void OnPropertyChanged( string propertyName)

if (PropertyChanged != null )

PropertyChanged( this , new PropertyChangedEventArgs (propertyName));

#endregion

Still reading? Then I’d recommend taking a look at some supplemental general information about ObservableCollection<T> or at how to make the an observable collection (or list) thread-safe .