问题
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?
回答1:
Reason
The
HandleCreatedraises just once. the problem is something else, it's because of the way thatOnHandleCreatedand data-binding has implemented inComboBox.
This is how OnHandleCreated method of the ComboBox works:
- It first raise
HandleCreatedevent. (Keep in mind,IsHandleCreatedis true at this point.) - Then for each item in
Itemscollection of the control, sends a CB_ADDSTRING native message to add the item to native combo box.
And this is how setting DataSource works:
- For each item in
DataSource, it first adds the item toItemscollection, then checks ifIsHandleCreatedis true, sends aCB_ADDSTRINGnative 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.
Solution
To solve the problem, you can use either of the following optoins:
You can delay the the
HandleCreatedevent code execution by usingBeginInvokeAs another option you can rely on
VisibleChangedevent.
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);
回答2:
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.
来源:https://stackoverflow.com/questions/53927091/why-is-the-combobox-doubling-its-items-when-being-created