2

我有一个表单,它有一个名为 的菜单MenuEdit,里面有一个 ToolStripMenuItem 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 个子项,所以我也必须创建这些子项,并附加它们的处理程序。

我正在使用框架 4.0。

4

3 回答 3

0

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

ToolStripItemCollection的方法Add调用该ToolStripItemCollection.SetOwner方法以用新所有者(您的上下文菜单)替换工具条的最后所有者(您的菜单条)

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

于 2014-07-16T18:13:38.250 回答
0

刚刚花了几个小时来找出如何以一种优雅、简单和有效的方式解决这个问题:

需要(例如):aboutToolStripMenuItem 作为 ToolStripMenuItem

  1. 创建一个新的 ContextMenuStrip:

    ContextMenuStrip ctx = new ContextMenuStrip();

  2. 使用原始 ToolStripMenuItem 项的数量创建一个新的 ToolStripItem[]

    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(鼠标位置);

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

    ctx.Closed += ctx_Closed;

    void ctx_Closed(对象发送者,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);
}
于 2014-11-13T14:06:36.570 回答
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
于 2020-04-30T15:30:40.193 回答