Hello! I am working on a C++/CLI Windows Forms project for .NET Framework 4.6.
I've been having a bit of trouble wrapping my head around the contradictory behavior of the ComboBox class.
My ComboBoxes are all DropDownLists, they are not editable.
What I would like to have is the ability to add (not remove, maybe this makes things easier) items to the combobox list at any time during program execution (regardless of whether the list has "dropped down" or not). This will be done by functions invoked from another Thread if that matters.
After playing around a bit, I noticed that the ComboBox behaves differently depending on whether it was actually dropped down when a new element was inserted.
Recreating this is simple:
In the Form constructor:
Just add a couple Labels for printing and a DropDownList-style ComboBox with 1 item in the list to a Form.
I tie a simple print function to the SelectedIndexChanged event of the ComboBox. It simply prints "Handler called" in the first label.
I also tie a simple print function to the DropDownClosed event that prints the SelectedIndex and SelectedItem in the second label.
In the Form Load event:
I launch a Thread which invokes a function every 10 seconds on the main thread.
This function adds a new element to a random position in the ComboBox list and prints out the SelectedIndex class member in the second label. My elements are all just strings that say "Item X", where X is the value of an incrementing global variable, which makes it easy to tell the difference between items.
We are interested in the scenario when a new element is inserted BEFORE the currently selected one (thus forcing it 1 position downwards and, apparently, incrementing the SelectedIndex).
There are 2 main cases: the drop-down list is visible or closed
When the list is CLOSED: the SelectedIndex is indeed incremented BUT the SelectedIndexChanged event is not triggered, even though the index was obviously changed. The selected element remains the same.
When the list is OPEN: the SelectedIndex also changes as the item moves down the list. The SelectedIndexChanged handler does not execute. The SelectedItem stays the same and is highlighted in the list as it moves down. HOWEVER! If I close the list by clicking outside the ComboBox (so I don't actually select another element), then the list closes and the ComboBox displays the element that occupies the INITIAL index of the item before it started moving down AND the SelectedIndex, SelectedItem magically revert to their old values. The SelectedIndexChanged handler is still not called.
So, for example, if the list was:
Item 0 [Selected]
And then a few insertions gave:
Item 0 [Selected]
The SelectedIndex will change from 0->1->2 while the list is VISIBLE and Item 0 remains visibly selected (SelectedItem also == "Item 0"), but, once I make the list disappear (I click somewhere outside the ComboBox), the SelectedIndex will jump back to 0 AND the ComboBox will display Item 2 as the currently selected item! And I will get NO notifications via events like SelectedIndexChanged whatsoever.
What bothers me is case 2 where the actual selected value changed even though I never actually selected it myself.
The biggest puzzle is where on earth were the initial index/item stored while items were being added?
We saw that SelectedIndex changed as the element moved down the list, so the starting index MUST have been placed somewhere else and then retrieved once the list was closed. But where?
Also, why does this happen anyway? On the one hand we visibly see the combobox keeping track of the item moving down the list, but then it suddenly decides to discard all that hard work and revert to the old index, thereby showing the complete opposite behavior.
It tracks the selected item and doesn't track it at the same time which is... contradictory. From the user's perspective, you at first think that your choice will stay the same (because it doesn't visibly change as items are added and the blue highlighted row stays on the initial selection) but then it switches when you close the list. Is there any way to prevent or circumvent this?