我有一个表格,其中有一个菜单叫 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。
一个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中。
只是花了一些时间来寻找如何以一种优雅、简单、高效的方式来解决这个问题。
要求(例如):aboutToolStripMenuItem作为ToolStripMenuItem。
创建一个新的ContextMenuStrip。
ContextMenuStrip ctx = new ContextMenuStrip();
创建一个新的ToolStripItem[],其数量为原来的ToolStripMenuItem项目的数量。
ToolStripItem[] itmArray = new ToolStripItem[aboutToolStripMenuItem.DropDownItems.Count]。
将ToolStripMenuItem项目复制到新的ToolStripItem[]中。
aboutToolStripMenuItem.DropDownItems.CopyTo(itmArray, 0)。
最后将ToolStripItem[]添加到ContextMenuStrip中,并在MousePosition处显示它。
ctx.Items.AddRange(itmArray);ctx.Show(MousePosition)。
不要忘记把项目放回原来的菜单项(注册上下文菜单的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);
}
我也遇到过类似的问题 读了这里的很多有用的东西,这个似乎很好用。
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