kirillandy-0739 avatar image
0 Votes"
kirillandy-0739 asked ·

Adding items to a ComboBox shows different behaviour

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]
Item 1
And then a few insertions gave:
Item 2
Item 3
Item 0 [Selected]
Item 1
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?

· 13
10 |1000 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

This will be done by functions invoked from another Thread if that matters.

It does matter, it's a big no-no, don't do it.
Do any UI control manipulation from the UI thread and see if you still have a problem.

0 Votes 0 ·

Um... I am doing UI manipulation on the UI thread, that's not the problem. I am aware that I can't just say combobox->Items->Add(...) on my second thread. I use BeginInvoke on my second thread every 10 seconds which executes a function that inserts a new item into the ComboBox list. What exactly is so wrong about that?
The problem is the weird behavior that occurs when you add items to a list that is open. The selected item doesn't visibly change until you close the list, at which point it just jumps back to the initial index.

0 Votes 0 ·

That should be OK then - it wasn't obvious to me that was what you were doing since you specifically worried about it being done from another thread.
Do you have a simple project that reproduces the issue that you can share?

0 Votes 0 ·
Show more comments

Additionally, I cannot replicate a simple example of my use case unless I use a 2nd thread. The program I am working on has the exact same basic architecture: a second thread that invokes UI updates at "arbitrary" points in time.

How can I add items to an open ComboBox list within 1 thread?
Add a Button that adds an item? Clicking it will cause the list to close and won't show the behavior I described.
Add items in the DropDown event? Not my use case. I will never have the need to deterministically add items when the user decides to open the list. Besides, I have not checked if this will also produce the behavior I described.

0 Votes 0 ·

If you need the 2'nd thread to reproduce it, that's fine, provided you're not breaking the rules, it's still a valid repro case.

0 Votes 0 ·

0 Answers