Jungle Coder

The musings of a third culture coder and missionary kid

Performance gotchas in .NET: BindingList<T>

Every programming framework has certain corner cases that can drain performance when mishandled. The .Net Framework is no exception. I’ve discovered a few in my work with C#. I’ll be blogging about these as I find them.

These are not micro-optimizations like using String.Concat instead of += "" over a small string. These problems will suck the performance straight out of your application, and are inconspicuous in the code, requiring a some kind of profiling to realize what’s going on.

One of these potential performance sinks is the BindingList collection, often used in Windows Forms projects when the form needs to be data-bound against a list of objects. It’s a handy class to have at your disposal. It gives the same methods for collection handing as the List collection, and binds to ComboBoxes and ListBoxes very easily.

There’s only one caveat: when BindingList is used incorrectly, it gets used in a Shelmiel the Painter algorithm. But it only does this under a certain set of conditions:

The first condition is that an empty BindingList (I’ll call it nameList) is bound to a ComboxBox or ListBox on your form.

var nameList = new BindingList();
ComboBox1.DataSource = nameList;

The second condition is that the BindingList is then populated in a loop or by using AddRange():

names = get10000MaleNamesFromFile();
foreach(string n in names)

Put these two together, and you get really bad performance. For 1000 names, it takes around 0.2-0.1 seconds. For 5000 names, it takes a little over 2 seconds. For 15000 names, it takes my computer somewhere on the order of 20 seconds to add the list(see the download at the end to test on your machine). That gets bad if I every had to deal with more than about 5000 names, but it will also get worse if the collection in question has a lot of properties that are accessed, such that even 500 items could be too many.

What’s going on here is an unseen inner loop with the call to NameList.Add(). In order to make bindings work, the BindingList class exposes an event called ListChanged, which provides two parameters to methods that handle it: An object reference that points to the BindingList, and a ListChangedEventArg that gives some information about the list change. It seems that ComboBoxes and ListBoxes enumerate the entire BindingList every time that the ListChanged event is fired. (This is effect is difficult to log, I’ll update if I get a code sample that does so).

There are two approaches to fix this:

1) Don’t set the BindingList as the Data Source of a Combo- or ListBox until the BindingList is completely filled. This keeps the ComboBox and ListBox from enumerating over items multiple times and taking a long time.

2) Turn off the ListChanged events while adding a lot of items to the BindindList. Using the example above, this approach is coded like so:

names = get10000MaleNamesFromFile();
//Turn off the ListChanged Events
NameList.RaiseListChangedEvents = false;
foreach(string n in names)
//Turn them back on.
NameList.RaiseListChangedEvents = true
//Notify the changes to the ComboBox

Either of these approaches takes the amount of time into the millisecond range, where 15000 records takes less time than the list of 1000 names did before. Now the code runs with linear performance. For anyone that wants to experiment with this performance issue, I wrote a small Windows Form that demonstrates the issue: you can download it here.

Published July 27th, 2013

Previously: The People you Play with...
Next: Mechanical and Creative Work


Nikola Malešević

Thanks so much, you saved me a lot of pain.


Good one!




Thank you sooo much for this post. I've been having trouble understanding why my 2 lists of 150 items was lagging out my application so badly. This made the application go from taking 3 seconds for each change to under half a second.


It's a good idea to use a finally block to turn list changed events back on, so that you can be sure they don't stay turned off after an exception (that's handled elsewhere).

Reqired fields are marked with a '*'