将一个现有的ToolStripMenuItem动态地添加到一个ContextMenu中,使它从原来的位置消失。

问题描述 投票:2回答:3

我有一个表格,其中有一个菜单叫 MenuEdit的工具条菜单项,其名称为 MenuEditElement 内。当我在列表视图上点击右键时,我想动态地创建一个上下文菜单,其中包含EditElement等内容。我是这样做的。

        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)

问题是,在右键点击之后 CM.Items.Add(MenuEditElement),MenuEditElement从MenuEdit中消失了,就像它从那里被移除以添加到上下文菜单中一样。有其他方法可以做到这一点吗?

我不希望创建一个与MenuEditItem相同的菜单,或者克隆它。这是因为MenuEditItem有5个子项,所以我也必须创建这些子项,同时附加它们的处理程序。

我使用的是Framework 4.0。

.net vb.net winforms contextmenu toolstripmenu
3个回答
0
投票

一个menuitem对象一次只能是一个菜单的一个项目。通过调用 Add 函数将menuitem对象分配给另一个菜单。您不是在创建一个新的对象。

你并不是在创建一个新的对象。Add 的方法调用ToolStripItemCollection的 ToolStripItemCollection.SetOwner 方法,用新的所有者(上下文菜单)替换工具条的上一个所有者(你的menustrip)。

来自 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

你可以看到,该项目从上一个菜单中删除,并添加了新的菜单。

那么你能做什么呢?

ToolStripMenuItem没有实现IClonable。

你需要做的是实例化一个新的对象。

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

现在你还需要为事件进行布线

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

然后把这个项目添加到你的上下文菜单中,而不是原来的项目。

CM.Items.Add(NewItem)

这将创建一个新的项目,它的外观和工作方式与MenuEditItem相同,然后将其放在ContextMenuStrip中。


0
投票

只是花了一些时间来寻找如何以一种优雅、简单、高效的方式来解决这个问题。

要求(例如):aboutToolStripMenuItem作为ToolStripMenuItem。

  1. 创建一个新的ContextMenuStrip。

    ContextMenuStrip ctx = new ContextMenuStrip();

  2. 创建一个新的ToolStripItem[],其数量为原来的ToolStripMenuItem项目的数量。

    ToolStripItem[] itmArray = new ToolStripItem[aboutToolStripMenuItem.DropDownItems.Count]。

  3. 将ToolStripMenuItem项目复制到新的ToolStripItem[]中。

    aboutToolStripMenuItem.DropDownItems.CopyTo(itmArray, 0)。

  4. 最后将ToolStripItem[]添加到ContextMenuStrip中,并在MousePosition处显示它。

    ctx.Items.AddRange(itmArray);ctx.Show(MousePosition)。

  5. 不要忘记把项目放回原来的菜单项(注册上下文菜单的Closed-Event)。

    ctx.Closed += ctx_Closed;

    void ctx_Closed(object sender, ToolStripDropDownClosedEventArgs e){ aboutToolStripMenuItem.DropDownItems.AddRange(itmArray);}。

现在都在一起了。

ToolStripItem[] itmArray;

private void dataGridView_CellMouseClick(object sender, DataGridViewCellMouseEventArgs e)
{
  if (e.Button == System.Windows.Forms.MouseButtons.Right)
  {
    itmArray = new ToolStripItem[aboutToolStripMenuItem.DropDownItems.Count];
    aboutToolStripMenuItem.DropDownItems.CopyTo(itmArray, 0);

    ContextMenuStrip ctx = new ContextMenuStrip();
    ctx.Closed += ctx_Closed;
    ctx.Items.AddRange(itmArray);
    ctx.Show(MousePosition);
  }
}

void ctx_Closed(object sender, ToolStripDropDownClosedEventArgs e)
{
  aboutToolStripMenuItem.DropDownItems.AddRange(itmArray);
}

0
投票

我也遇到过类似的问题 读了这里的很多有用的东西,这个似乎很好用。

Private Sub PopulateContextMenu()
        ContextMenuStrip1.Items.Clear()
        For Each m In MenuStrip2.Items
            Dim clone As New ToolStripMenuItem
            clone = CloneMenu(m)
            If clone IsNot Nothing Then
                ContextMenuStrip1.Items.Add(clone)
            End If
        Next
    End Sub 
Friend Function CloneMenu(m As ToolStripMenuItem) As ToolStripMenuItem
    Dim newitem As New ToolStripMenuItem()
    With newitem
        .Name = m.Name
        .Text = m.Text
        .ToolTipText = m.ToolTipText
        .Enabled = m.Enabled
        'Add any other things you want to preserve, like .Image
        'Not much point preserving Keyboard Shortcuts on a context menu
        'as it's designed for a mouse click.
        If m.HasDropDownItems Then
            For Each sm In m.DropDownItems
                If TypeOf (sm) Is ToolStripMenuItem Then
                    newitem.DropDownItems.Add(CloneMenu(sm))
                End If
            Next
        End If
    End With
    AddHandler newitem.Click, AddressOf m.PerformClick
    Return newitem
End Function
© www.soinside.com 2019 - 2024. All rights reserved.