none
Listbox Problem after displaying dialog box RRS feed

  • Question

  • I've found an interesting problem.  If I display a dialog box (e.g. MessageBox.Show or MyForm.ShowDialog) in a textbox's event such as Leave then clicking into a listbox doesn't seem to register the mouse click.

     

    My environment is Windows XP, VS 2008, VB.Net.

     

    I replicated this on a simple form as follows:

    1. Create a new form in .net 2008

    2. Add a listbox called ListBox1

    3. Add a few items to the listbox

    4. Add a SelectedIndexChanged event handler to the listbox and do something in it.

    5. Add a textbox called TextBox1

    6. Add a Leave event handler and have it display a MsgBox

    7. Run the form

    8. Click into the textbox

    9. Click into the listbox - the message displays

    10. Click OK - the SelectedIndexChanged has not fired yet.  In fact as you mouse over the listbox the selection changes.

    11. Click anywhere, it doesn't even need to be on the form, and it will take the selection and fire the event.

     

    Here is the simple event handling code I used:

     

    Public Class Form1

     

    Private Sub ListBox1_SelectedIndexChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ListBox1.SelectedIndexChanged

    Me.TextBox1.Text = Me.ListBox1.Text

    End Sub

     

    Private Sub TextBox1_Leave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.Leave

    MsgBox("leaving")

    End Sub

     

    End Class

     

    I haven't been able to find any hit on this problem.  My current work around is to use my own form to display messages and to use Show, not ShowDialog

     

    Any ideas?  Is thsi a bug? 

     

    Thanks,

    Carl

    Wednesday, December 3, 2008 6:23 PM

Answers

  • Never change the focus in a focusing event, controls get fatally confused by it.  One workaround is this:

      Private Sub TextBox1_Leave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.Leave
        Me.BeginInvoke(New MethodInvoker(AddressOf DelayedLeave))
      End Sub

      Private Sub DelayedLeave()
        MsgBox("okay now")
      End Sub

    Wednesday, December 3, 2008 6:57 PM
    Moderator

All replies

  • Never change the focus in a focusing event, controls get fatally confused by it.  One workaround is this:

      Private Sub TextBox1_Leave(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TextBox1.Leave
        Me.BeginInvoke(New MethodInvoker(AddressOf DelayedLeave))
      End Sub

      Private Sub DelayedLeave()
        MsgBox("okay now")
      End Sub

    Wednesday, December 3, 2008 6:57 PM
    Moderator
  • Hans,

     

    Thank you for background and the work around.  It works well for my immediate need.  I had hoped to be able to query the user before going on to processing the selection but since the asynchronous display occrs after the SelectedIndexChanged event has occured that won't work.  I'll have to consider my options for querying the user at a later date when/if it becomes an issue.

     

    A note to others:  Using EndInvoike, which blocks the main thread until the asynchronous call completes, puts one right back to the original problem - the listbox looses the focus to the dialog box and then gets confused.

     

    Thanks Again,

    Carl

    Thursday, December 4, 2008 3:00 PM
  • Here is a more generalized version that lets you pass parameters to the delegate:

     

    Private Delegate Sub DelayedMessageDisplay(ByVal msg As String, ByVal title As String, ByVal msgButtons As MessageBoxButtons, ByVal msgIcons As MessageBoxIcon)

     

    Private Sub RISComboBox_Validating(ByVal sender As Object, ByVal e As System.ComponentModel.CancelEventArgs) Handles Me.Validating

    ...snip...

    Dim msgDisplayer As DelayedMessageDisplay = AddressOf DelayedMessageBoxDisplay

    BeginInvoke(msgDisplayer, New Object(3) {"The text you entered, '" & Me.Text & "', is not in the list. The change will be discarded.", _

    "Entry Not In List", _

    MessageBoxButtons.OK, _

    MessageBoxIcon.Warning})

    ...snip...

    End Sub

     

    Private Sub DelayedMessageBoxDisplay(ByVal msg As String, ByVal title As String, ByVal msgButtons As MessageBoxButtons, ByVal msgIcons As MessageBoxIcon)

    MessageBox.Show(msg, title, msgButtons, msgIcons)

    End Sub

     

    Hope it's useful,

    Carl

    Thursday, December 4, 2008 3:48 PM