WinForms ComboBox data binding gotcha
This has to do with how data bindings are set up in the dotnet framework, especially the BindingContext
. On a high level it means that if you haven't specified otherwise each form and all the controls of the form share the same BindingContext
. When you are setting the DataSource
property the ComboBox
will use the BindingContext
to get a ConcurrenyMangager
that wraps the list. The ConcurrenyManager
keeps track of such things as the current selected position in the list.
When you set the DataSource
of the second ComboBox
it will use the same BindingContext
(the forms) which will yield a reference to the same ConcurrencyManager
as above used to set up the data bindings.
To get a more detailed explanation see BindingContext.
A better workaround (depending on the size of the datasource) is to declare two BindingSource
objects (new as of 2.00) bind the collection to those and then bind those to the comboboxes.
I enclose a complete example.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
namespace WindowsFormsApplication2
{
public partial class Form1 : Form
{
private BindingSource source1 = new BindingSource();
private BindingSource source2 = new BindingSource();
public Form1()
{
InitializeComponent();
Load += new EventHandler(Form1Load);
}
void Form1Load(object sender, EventArgs e)
{
List<string> myitems = new List<string>
{
"Item 1",
"Item 2",
"Item 3"
};
ComboBox box = new ComboBox();
box.Bounds = new Rectangle(10, 10, 100, 50);
source1.DataSource = myitems;
box.DataSource = source1;
ComboBox box2 = new ComboBox();
box2.Bounds = new Rectangle(10, 80, 100, 50);
source2.DataSource = myitems;
box2.DataSource = source2;
Controls.Add(box);
Controls.Add(box2);
}
}
}
If you want to confuse yourself even more then try always declaring bindings in the constructor. That can result in some really curious bugs, hence I always bind in the Load event.