How do I provide a foolproof auto-dropdown for a combo box receiving the focus?

RobertAlanGustafsonII

Active member
Joined
Sep 16, 2023
Messages
42
Programming Experience
10+
WHAT I HAVE:
Visual Basic2019/ 2022, WinForms, .NET Framework 4.6.1 and up

MY PROBLEM:
I'm trying to come up with code that causes the list of a combo box to drop down when the control gets the focus. The simplest way is to include the following code in either the GotFocus or Enter event procedure:

Auto-dropdown code:
If Not control.DroppedDown Then
    control.DroppedDown = True
End If

The code works fine when one tabs to the control. When one clicks on the control, however, the list usually (but not always) drops down then closes up again. How do I fix this issue? Please provide any answer ASAP, in VB.NET, and as simply as possible.
 
Last edited:
I see the open/close happens when style is DropDown and clicking the combobox button, or when style is DropDownList and clicking anywhere. In both cases the control itself is dropping, and the code interferes with this. I suggest yielding the Enter event and see if manually dropping is necessary after that:
VB.NET:
Private Async Function YieldDropDown(cb As ComboBox) As Task
    Await Task.Yield
    If Not cb.DroppedDown Then
        cb.DroppedDown = True
    End If
End Function
Then in Enter event call
VB.NET:
Dim unused = YieldDropDown(ComboBox1)
YieldDropDown is awaitable if you need to do more in Enter event after this call.
 
I see the open/close happens when style is DropDown and clicking the combobox button, or when style is DropDownList and clicking anywhere. In both cases the control itself is dropping, and the code interferes with this. I suggest yielding the Enter event and see if manually dropping is necessary after that:
VB.NET:
Private Async Function YieldDropDown(cb As ComboBox) As Task
    Await Task.Yield
    If Not cb.DroppedDown Then
        cb.DroppedDown = True
    End If
End Function
Then in Enter event call
VB.NET:
Dim unused = YieldDropDown(ComboBox1)
YieldDropDown is awaitable if you need to do more in Enter event after this call.

Have you already tested this?
 
Yes, why do you ask?
 
WHAT I HAVE:
Visual Basic2019/ 2022, WinForms, .NET Framework 4.6.1 and up

MY PROBLEM:
I'm trying to come up with code that causes the list of a combo box to drop down when the control gets the focus. The simplest way is to include the following code in either the GotFocus or Enter event procedure:

Auto-dropdown code:
If Not control.DroppedDown Then
    control.DroppedDown = True
End If

The code works fine when one tabs to the control. When one clicks on the control, however, the list usually (but not always) drops down then closes up again. How do I fix this issue? Please provide any answer ASAP, in VB.NET, and as simply as possible.

It's a common issue in Windows Forms where programmatically dropping down a ComboBox in the GotFocus or Enter event can sometimes cause the dropdown to immediately close when the control is clicked, due to the timing of events. The click event's default handling can sometimes interfere with the programmatically opened dropdown.
It's a common issue in Windows Forms where programmatically dropping down a ComboBox in the GotFocus or Enter event can sometimes cause the dropdown to immediately close when the control is clicked, due to the timing of events. The click event's default handling can sometimes interfere with the programmatically opened dropdown.

A simple and often effective way to fix this in VB.NET is to defer the action of setting DroppedDown = True using Control.BeginInvoke. This allows the initial click event processing to complete before the dropdown is forced open.
Revised:
Private Sub ComboBox1_GotFocus(sender As Object, e As EventArgs) Handles ComboBox1.GotFocus
    Dim control = DirectCast(sender, ComboBox)
    ' Defer the dropdown action until after the current UI message processing
    control.BeginInvoke(New Action(Sub()
                                       If Not control.DroppedDown Then
                                           control.DroppedDown = True
                                       End If
                                   End Sub))
End Sub
The control.BeginInvoke(...) schedules the code within the Sub() to be executed on the UI thread after any pending UI messages (including those from the click event) have been processed.
The New Action(Sub() ... End Sub) creates an anonymous delegate that contains the code to be executed later.
Also: If Not control.DroppedDown Then control.DroppedDown = True remains the core logic to only drop down the list if it's not already open. However, you can use the same approach in the Enter event as well:
Control:
Private Sub ComboBox1_Enter(sender As Object, e As EventArgs) Handles ComboBox1.Enter
    Dim control = DirectCast(sender, ComboBox)
    ' Defer the dropdown action until after the current UI message processing
    control.BeginInvoke(New Action(Sub()
                                       If Not control.DroppedDown Then
                                           control.DroppedDown = True
                                       End If
                                   End Sub))
End Sub
Using BeginInvoke provides a simple way to work around the timing conflict between the click event and the programmatic dropdown, ensuring the list stays open when the control is clicked.
 
Back
Top