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 |