.netvb.nettreeviewcontextmenustrip

ContextMenuStrip item to perform different actions depending on who calls it


I have created a ContextMenuStrip with three different items. Then I have a TreeView with a parent and child nodes. I assigned the ContextMenuStrip to both nodes like so:

fatherNode.ContextMenuStrip = menuNodes
childNode.ContextMenuStrip = menuNodes

The problem is that the items from the menu must perform different actions depending on which node calls the menu item. In other words, for example if the first item on the menu is "create", it will create something very specific if the father node calls it and a different thing if the child calls the same menu item.

Hopefully I was able to explain what I mean and sorry I do not have any code because I have no clue how I can achieve this.


Solution

  • Suppose you have two methods:

    Private Sub ParentNodeMethod()
        Console.WriteLine("Parent Node Method")
    End Sub
    
    Private Sub ChildNodeMethod()
        Console.WriteLine("Child Node Method")
    End Sub
    

    ... and you have a ContextMenuStrip for a TreeView control and you want a specific menu strip item (ToolStripMenuItem) calls - on click - one of them according to which TreeNode is clicked.

    You could utilize the Action delegate and create different actions that invokes different methods and assign them to the Tag properties of the TreeNode objects in question, handle the TreeView.NodeMouseClick to show the ContextMenuStrip and pass the right action, and handle the ItemClicked event of the ContextMenuStrip to invoke it.

    Replace you code with:

    '//
    parentNode.Tag = New Action(AddressOf ParentNodeMethod)
    childNode.Tag = New Action(AddressOf ChildNodeMethod)
    '//
    
    Private Sub TreeView1_NodeMouseClick(sender As Object,
                                         e As TreeNodeMouseClickEventArgs) _
                                         Handles TreeView1.NodeMouseClick
    
        If e.Button = MouseButtons.Right AndAlso TypeOf e.Node.Tag Is Action Then
            ContextMenuStrip1.Items(0).Tag = e.Node.Tag
            ContextMenuStrip1.Show(TreeView1, e.Location)
        End If
    End Sub
    
    Private Sub ContextMenuStrip1_ItemClicked(sender As Object,
                                              e As ToolStripItemClickedEventArgs) _
                                              Handles ContextMenuStrip1.ItemClicked
        If TypeOf e.ClickedItem.Tag Is Action Then
            DirectCast(e.ClickedItem.Tag, Action)()
            e.ClickedItem.Tag = Nothing
        End If
    End Sub
    

    Another way is to create a Dictionary(Of TreeNode, Action) instead of assigning the actions to the Tag properties:

    'Class member
    Private ReadOnly dict As New Dictionary(Of TreeNode, Action)
    '//
    
    dict.Add(parentNode, New Action(AddressOf ParentNodeMethod))
    dict.Add(childNode, New Action(AddressOf ChildNodeMethod))
    '//
    
    Private Sub TreeView1_NodeMouseClick(sender As Object,
                                         e As TreeNodeMouseClickEventArgs) _
                                         Handles TreeView1.NodeMouseClick
    
        Dim a As Action = Nothing
    
        If e.Button = MouseButtons.Right AndAlso dict.TryGetValue(e.Node, a) Then
            ContextMenuStrip1.Items(0).Tag = a
            ContextMenuStrip1.Show(TreeView1, e.Location)
        End If
    End Sub
    
    Private Sub ContextMenuStrip1_ItemClicked(sender As Object,
                                              e As ToolStripItemClickedEventArgs) _
                                              Handles ContextMenuStrip1.ItemClicked
        If TypeOf e.ClickedItem.Tag Is Action Then
            DirectCast(e.ClickedItem.Tag, Action)()
            e.ClickedItem.Tag = Nothing
        End If
    End Sub
    

    Alternatively and as already mentioned by @Jimi, if the TreeNode objects of the same Level should call the same method, then use this property to decide which method should be called.