KnowDotNet

Handling TreeView & ComboBox Click Events

AfterSelect Event Does Not Fire When Same Value Selected

by Les Smith

Why does the AfterSelect event not fire if the user selects the same node from a TreeView twice in a row?  The same thing happens in a ComboBox.

There is a subtile anamoly regarding determination of which node was selected when when a TreeView node is clicked.  In VB6 you could use the click event and reference the SelectedNode.  If you do this in .NET, you will get the node that was clicked previously or Null if no node was clicked previously.  This is due to the fact that the new selection has not been set at the time the Click event fires.

MSDN tells you to use the
AfterSelect event instead of the Click event.  This works fine unless the user clicks the same node twice in a row.  In that case the AfterSelect event will not fire because the selection is already made.  Therefore, if you are using a TreeView for a menu or if for any reason the user clicks the same node twice, the AfterSelect event will not fire and you will not take any action in the AfterSelect event no matter how many times the user clicks the node.  This will immediately generate frustration on the part of the user.

The answer to this problem is to use both the
AfterSelect and Click events in concert.  To do this, dimension a module level Boolean.  Also set up a Timer on the form or a Timer object in a Class.  Then implement the forllowing type of code.

This code was taken from my book "Writing Add-ins for Visual Studio NET," published by Apress.

      Private mbMenuClicked As Boolean

      Private Sub tvMenu_AfterSelect(ByVal sender As Object, _
        
ByVal e As System.Windows.Forms.TreeViewEventArgs) _
        
Handles tvMenu.AfterSelect
        
Dim i As Integer
         mbMenuClicked = False
         CallTVSelection(e.Node.Text)
      
End Sub

      Private Sub tvMenu_Click(ByVal sender As Object, _
        
ByVal e As System.EventArgs) Handles tvMenu.Click
        
' At the time the click event fires, the selection
         ' of the just clicked
         ' node has not yet taken place, so if you try to
         ' determine the node clicked in the click event, you
         ' will always find the node which was selected prior
         ' to the click. To get around this mismatch of event
         ' firing, we start a timer which will fire in 50ms
         ' If the AfterSelect event fires, because a new selection
         ' was made by the user, it will tell the Timer Event to
         ' ignore the interrupt.
         mbMenuClicked = True
         Timer1.Enabled = True
      End Sub

      Private Sub Timer1_Tick(ByVal sender As System.Object, _
        
ByVal e As System.EventArgs) Handles Timer1.Tick
        
' If the boolean, mbMenuClicked is True, that means the
         ' AfterSelect event did not fire, and the Click Event
         ' has asked us to display the current selection in
         ' the treeview.
         Dim s As String

         If mbMenuClicked Then
            mbMenuClicked = False
            If Not tvMenu.SelectedNode Is Nothing Then
               CallTVSelection(tvMenu.SelectedNode.Text)
            
End If
         End If
         Timer1.Enabled = False
      End Sub

      Shared Sub CallTVSelection(ByVal tvSelText As String)
        
Select Case UCase(tvSelText)
            
Case "BLOCK COMMENT"
              
Call BlockComment()
            
Case "UNCOMMENT"
              
Call BlockUnComment()
            
Case Else
               MsgBox("Please click on a Child Node.", _
                  MsgBoxStyle.Information, "Unknown Request")
        
End Select
      End Sub