.netvb.netwinformscontextmenutoolstripmenu

Adding an existing ToolStripMenuItem to a ContextMenu dynamically makes it disappear from its original place


I have a Form that has a menu called MenuEdit, with a ToolStripMenuItem called MenuEditElement inside. When I right click on a listview, I want to create a Context Menu dynamically, containing EditElement, among other things. I'm doing it like this:

        Dim CM As New ContextMenuStrip
        Dim Submenu As ToolStripMenuItem = CM.Items.Add("New", ImageHolder.Images("New"))
        CM.Items.Add(New ToolStripSeparator)
        CM.Items.Add(MenuEditElement)
        CM.Show(ListView, e.Location)

The problem is that, right after CM.Items.Add(MenuEditElement), MenuEditElement disappears from MenuEdit, as if it had been removed from there to be added to the context menu. Is there another way to do this?

I wouldn't want to be creating an identical menu to MenuEditItem, or to clone it. This is because MenuEditItem has 5 subitems, so I would have to create those too, along with attaching their handlers.

I'm using Framework 4.0.


Solution

  • A menuitem object can only be an item of one menu at a time. By calling the Add function you assign the menuitem object to another menu. You are not creating a new object.

    The Add method of the ToolStripItemCollection calls the ToolStripItemCollection.SetOwner method to replace the last owner of the toolstripitem (your menustrip) with the new owner (your contextmenu)

    From System.Windows.Forms:

        Public Function Add(value As ToolStripItem) As Integer
            Me.CheckCanAddOrInsertItem(value)
            Me.SetOwner(value)
            Dim result As Integer = AddressOf MyBase.InnerList.Add(value)
            If Me.itemsCollection AndAlso Me.owner IsNot Nothing Then
                Me.owner.OnItemAdded(New ToolStripItemEventArgs(value))
            End If
            Return result
        End Function
        Private Sub SetOwner(item As ToolStripItem)
            If Me.itemsCollection AndAlso item IsNot Nothing Then
                If AddressOf item.Owner IsNot Nothing Then
                    AddressOf AddressOf item.Owner.Items.Remove(item)
                End If
                item.SetOwner(Me.owner)
                If AddressOf item.Renderer IsNot Nothing Then
                    AddressOf item.Renderer.InitializeItem(item)
                End If
            End If
        End Sub
    

    You can see that the item is removed from the last menu and added the new one.

    So what can you do?

    ToolStripMenuItem does not implement IClonable.

    What you need to do is instantiate a new object

    Dim NewItem as New ToolStripMenuItem
    With NewItem
       .Text = MenuEditElement.Text
       .Image = MenuEditElement.Image
       'Rinse repeat for other important properties
    End With
    

    Now you also need to wire up the events

    AddHandler NewItem.Click, AddressOf HandleEditClicked 'Replace with the method that handles MenuEditItem.Clicked
    

    Then add this item to your context menu instead of the original item

    CM.Items.Add(NewItem)
    

    This will create a new item that looks and works the same way as MenuEditItem and this is then placed in the ContextMenuStrip