Complex DataBinding accepts as a data source either an IList or an IListSource

If you try to set a list control’s DataSource to a type it can’t handle, then you’ll get the following exception:

System.ArgumentException: Complex DataBinding accepts as a data source either an IList or an IListSource. (Parameter ‘value’)
at System.Windows.Forms.ListControl.set_DataSource(Object value)

Note: This applies to all controls that subclass ListControl, such as ComboBox and ListBox.

This is confusing because the DataSource property is of type object, but it can only be set to IList or IListSource. It’s type unsafe, because it enforces this type constraint at runtime.

To fix the problem, convert your data source object to a list with .ToList() or use a BindingSource. I’ll show examples below.

Solution – Use .ToList()

Let’s say you want to use a dictionary’s keys as the data source.

You can’t just set DataSource = dictionary.Keys, because KeyCollection doesn’t implement IList / IListSource.

Instead, you can convert the keys to a list by calling .ToList():

var map = new Dictionary<string, string>()
{
	["a"] = "b"
};

cbVehicleTypes.DataSource = map.Keys.ToList();
Code language: C# (cs)

Read more about initializing a dictionary.

The same problem happens when you try to use a Linq query as the data source, because a Linq query returns an IEnumerable. To use this as a data source, you have to call .ToList(), like this:

cbVehicleTypes.DataSource = map.Keys.Where(t => t.Length > 1).ToList();
Code language: C# (cs)

Solution – Use BindingSource

When you can’t directly set your object as the data source, and you don’t want to (or can’t) convert it to a list, then you can use a BindingSource instead.

For example, to use a dictionary’s keys as the data source, you can use a BindingSource with the dictionary like this:

var map = new Dictionary<string, string>()
{
	["a"] = "b"
};

cbVehicleTypes.DataSource = new BindingSource(map, "Key");
Code language: C# (cs)

This doesn’t work well with Linq queries. It works fine if the query returns something, but if your Linq query returns nothing, then the control will show something strange, like System.Linq.Enumerable+WhereEnumerableIterator`1[System.String].

Stick with .ToList() if you’re using a Linq query as the data source to avoid having to deal with this.

Leave a Comment