Reputation: 16340
I'm creating a combobox programmatically as follows:
var cbo = new ComboBox();
cbo.HandleCreated += (s, e) =>
{
cbo.DataSource = mylist;
};
When I do the above, the combobox displays double the items contained in the list. However, when I do the following, the combobox displays the correct number of items:
var cbo = new ComboBox() {
DataSource = mylist
};
Why does this happen?
Upvotes: 2
Views: 717
Reputation: 125312
The
HandleCreated
raises just once. the problem is something else, it's because of the way thatOnHandleCreated
and data-binding has implemented inComboBox
.
This is how OnHandleCreated
method of the ComboBox
works:
HandleCreated
event. (Keep in mind, IsHandleCreated
is true at this point.)Items
collection of the control, sends a CB_ADDSTRING
native message to add the item to native combo box. And this is how setting DataSource
works:
DataSource
, it first adds the item to Items
collection, then checks if IsHandleCreated
is true, sends a CB_ADDSTRING
native message to add the item to native combo box. So when you set DataSource
in HandleCreated
event, for each item it sends CB_ADDSTRING
native message twice.
That's why you see items twice in the drop-down and at the same time Items.Count
shows correct count. Also it you click on additional item (the last half of the items) you will receive an index out of range exception.
To solve the problem, you can use either of the following optoins:
You can delay the the HandleCreated
event code execution by using BeginInvoke
As another option you can rely on VisibleChanged
event.
Option 1 - HandleCreated + BeginInvoke
var mylist = Enumerable.Range(1, 5).ToList();
var myvalue = 2;
var cbo = new ComboBox();
cbo.HandleCreated += (obj, args) =>
{
BeginInvoke(new Action(() =>
{
cbo.DataSource = mylist;
cbo.SelectedIndex = mylist.IndexOf(myvalue);
}));
};
this.Controls.Add(cbo);
Option 2 - VisibleChanged
var mylist = Enumerable.Range(1, 5).ToList();
var myvalue = 2;
var cbo = new ComboBox();
cbo.VisibleChanged+= (obj, args) =>
{
cbo.DataSource = mylist;
cbo.SelectedIndex = mylist.IndexOf(myvalue);
};
this.Controls.Add(cbo);
Upvotes: 3
Reputation: 3638
This code duplicates the record, because on your initialization of combobox it will hit the event HandleCreated which will add your list to the combobox. Then after finishing the initialization, the execution of the code will hit the event HandleCreated again since the first one that execute that event is from initialization, and the second one is from the run time execution itself.
var cbo = new ComboBox(); //initialization
//below this comment is the event
cbo.HandleCreated += (s, e) =>
{
cbo.DataSource = mylist;
};
P.S.
There's a better way on populating comboboxes in C# WinForms; every control (combobox, textbox, etc.) have their different events. You can check on that first rather than creating your event.
Upvotes: 3