Displaying a message box after using ListBoxName.List() in a double-click event disables all other UserForm controls

Article contributed by Robin Seeländer, Anna-Karin Bohman and Dave Rado

Using ListBoxName.LIst() to populate a list box is much faster in the case of large arrays than using AddItem. However, this method does have one unfortunate bug.

If, in the double-click event of a listbox, you display a message box and then repopulate the contents of the listbox from an array using ListBox1.List = ArrayName, then the user cannot click any other button in the UserForm unless they first hover with the mouse over the listbox!

The problem does not occur if you use AddItem to repopulate the listbox, rather than using the List method.

Steps to reproduce

Create a UserForm called UF, and add a listbox called LB and an OK button called cmdOK.

In the main module:

Option Explicit

Sub
RunUF()
    UF.Show
End Sub

In the UserForm module:

Option Explicit

Private Sub
cmdOK_Click()
    Unload Me
End Sub

Private Sub LB_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Dim ListArray As Variant
    MsgBox "Here is a message"
    ListArray = Array("4", "5")
    LB.List() = ListArray
End Sub

Private Sub UserForm_Initialize()
Dim ListArray As Variant
    ListArray = Array("1", "2", "3", "4")
    LB.List() = ListArray
End Sub

Run the code, click OK on the message box, and then try to click OK on the UserForm – you can't!

Then hover over the list box and click OK again – now you can!

Using AddItem in the Initialize event makes no difference; it's only when repopulating a listbox after displaying a message box that the .List method causes problems.

(Note for any MS developers who may read this: strictly speaking, it isn't the message box as such that causes the problem, it's the fact that displaying the message box prevents the mouse from hovering over the listbox immediately after double-clicking. If you don't display a message box, the mouse will automatically be hovering over the list box, hence the problem doesn't arise  If you use an API call to immediately set the mouse to coordinates 0,0 on the screen after copying the array to the listbox, you do get the problem without displaying a message box. Or if you displayed a second UserForm on top of the first, you would get the problem. But in real world applications, the bug is only likely to occur if you do display a message box.)

Workaround 1

One workaround is to use AddItem instead of the List method; but as previously mentioned, the List method is much faster, if it's a large array.

Workaround 2

Hide and then re-show the UserForm. This is more elegant than it might appear at first sight, because the user will not see the dialog disappear and reappear – and it's very fast. So in the above example, the following works:

Private Sub LB_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Dim ListArray As Variant
    MsgBox "Here is a message"
    ListArray = Array("4", "5")
    LB.List() = ListArray
    Me.Hide
    Me.Show
End Sub

Notes

1.

The line Me.Show must be the final line in the double-click event procedure. Any code in that procedure that follows that line will not fire until you unload the UserForm.

2.

The Activate event fires whenever you re-Show the UserForm (the Initialize event doesn't, though). So if you have written an Activate Event procedure, you will need to use a Boolean variable to prevent your Activation code from running twice, like this:

Option Explicit

Dim AlreadyActivated As Boolean

Private Sub cmdOK_Click()
    AlreadyActivated = False
    Unload Me
End Sub

Private Sub LB_DblClick(ByVal Cancel As MSForms.ReturnBoolean)
Dim ListArray As Variant
    MsgBox "Here is a message"
    ListArray = Array("4", "5")
    LB.List() = ListArray
    Me.Hide
    Me.Show
End Sub

Private Sub UserForm_Initialize()
Dim ListArray As Variant
    ListArray = Array("1", "2", "3", "4")
    LB.List() = ListArray
End Sub

Private Sub UserForm_Activate()
    If Not AlreadyActivated Then
        'Your code here
    End If
    AlreadyActivated = True
End Sub