如何使用递归提取 ContextMenuStrip 的所有 ToolStripMenuItems?
How to extract all ToolStripMenuItems of a ContextMenuStrip using recursion?
我正在尝试将所有项目从 ContextMenuStrip 提取到 List(Of ToolStripMenuItem)
。
我可以获得 DataGridView 的 ContextMenuStrip 的引用,然后 - 使用递归函数 - 我想提取所有 ToolStripMenuItems
的 Name
和 Text
属性,不包括 [=16] =],如果有的话。
我使用这个代码:
allItem = New List(Of Control)
Dim lstDbg As List(Of Control) = FindControlRecursive(allItem, form, GetType(DataGridView))
Dim dictRes As New Dictionary(Of String, String)
For Each dbgCtrl As Control In lstDbg
If dbgCtrl.Name <> "" Then
For Each mnuStrip As ToolStripItem In dbgCtrl.ContextMenuStrip.Items
If mnuStrip.GetType() = GetType(ToolStripMenuItem) Then
Dim lstItem As New List(Of ToolStripMenuItem)
Dim lstTS As List(Of ToolStripMenuItem) = FindControlRecursive_ContextMenu(lstItem, mnuStrip, GetType(ToolStripMenuItem))
For Each item As ToolStripMenuItem In lstTS
dictRes.Add(item.Name, item.Text)
Next
End If
Next
End If
Next
递归的函数是FindControlRecursive_ContextMenu()
:
Public Function FindControlRecursive_ContextMenu(ByVal list As List(Of ToolStripMenuItem), ByVal parent As ToolStripMenuItem, ByVal ctrlType As System.Type) As List(Of ToolStripMenuItem)
If parent Is Nothing Then Return list
If parent.GetType Is ctrlType Then
list.Add(parent)
End If
For Each child As ToolStripMenuItem In parent.DropDown.Items
FindControlRecursive_ContextMenu(list, child, ctrlType)
Next
Return list
End Function
有效,但如果下拉列表中有 ToolStripSeparator
,我没有 DropDown.Items
元素,函数会生成异常。
如何跳过 ToolStripSeparators 并使用下一个“子”调用递归函数?
因为只有 ToolStripMenuItem are needed, you can simply filter the ContextMenuStrip.Items collection beforehand, collecting only Item of that specific type. The Collection.OfType([Type]) method is commonly used for this. OfType()
only returns Items of the type specified: ToolStripSeparator 类型的 sub-items 不属于该类型,所以它不会包含在过滤集合中(其他组件类型,如 ToolStripTextBox、ToolStripComboBox 等也不会) .
递归函数可以是一个 iterator which returns an IEnumerable(Of ToolStripMenuItem)
,它产生在 for each
循环中找到的每个项目。
调用主方法,例如:
► 将 Option Strict
、Option Explicit
和 Option Infer
设置为 On
Dim cmsItems As Dictionary(Of String, String) = GetAllContextMenuItems(contextMenuStrip1)
Imports System.Linq
Private Function GetAllContextMenuItems(contextMenu As ContextMenuStrip) As Dictionary(Of String, String)
If contextMenu Is Nothing OrElse (Not contextMenu.HasChildren) Then Return Nothing
Dim dict = New Dictionary(Of String, String)
For Each item As ToolStripMenuItem In contextMenu.Items.OfType(Of ToolStripMenuItem)
dict.Add(item.Name, item.Text)
For Each subItem In GetSubMenuItems(item)
dict.Add(subItem.Name, subItem.Text)
Next
Next
Return dict
End Function
Private Iterator Function GetSubMenuItems(parent As ToolStripMenuItem) As IEnumerable(Of ToolStripMenuItem)
For Each item As ToolStripMenuItem In parent.DropDownItems.OfType(Of ToolStripMenuItem)
If item.HasDropDownItems Then
For Each subItem As ToolStripMenuItem In GetSubMenuItems(item)
Yield subItem
Next
Else
Yield item
End If
Next
End Function
我正在尝试将所有项目从 ContextMenuStrip 提取到 List(Of ToolStripMenuItem)
。
我可以获得 DataGridView 的 ContextMenuStrip 的引用,然后 - 使用递归函数 - 我想提取所有 ToolStripMenuItems
的 Name
和 Text
属性,不包括 [=16] =],如果有的话。
我使用这个代码:
allItem = New List(Of Control)
Dim lstDbg As List(Of Control) = FindControlRecursive(allItem, form, GetType(DataGridView))
Dim dictRes As New Dictionary(Of String, String)
For Each dbgCtrl As Control In lstDbg
If dbgCtrl.Name <> "" Then
For Each mnuStrip As ToolStripItem In dbgCtrl.ContextMenuStrip.Items
If mnuStrip.GetType() = GetType(ToolStripMenuItem) Then
Dim lstItem As New List(Of ToolStripMenuItem)
Dim lstTS As List(Of ToolStripMenuItem) = FindControlRecursive_ContextMenu(lstItem, mnuStrip, GetType(ToolStripMenuItem))
For Each item As ToolStripMenuItem In lstTS
dictRes.Add(item.Name, item.Text)
Next
End If
Next
End If
Next
递归的函数是FindControlRecursive_ContextMenu()
:
Public Function FindControlRecursive_ContextMenu(ByVal list As List(Of ToolStripMenuItem), ByVal parent As ToolStripMenuItem, ByVal ctrlType As System.Type) As List(Of ToolStripMenuItem)
If parent Is Nothing Then Return list
If parent.GetType Is ctrlType Then
list.Add(parent)
End If
For Each child As ToolStripMenuItem In parent.DropDown.Items
FindControlRecursive_ContextMenu(list, child, ctrlType)
Next
Return list
End Function
有效,但如果下拉列表中有 ToolStripSeparator
,我没有 DropDown.Items
元素,函数会生成异常。
如何跳过 ToolStripSeparators 并使用下一个“子”调用递归函数?
因为只有 ToolStripMenuItem are needed, you can simply filter the ContextMenuStrip.Items collection beforehand, collecting only Item of that specific type. The Collection.OfType([Type]) method is commonly used for this. OfType()
only returns Items of the type specified: ToolStripSeparator 类型的 sub-items 不属于该类型,所以它不会包含在过滤集合中(其他组件类型,如 ToolStripTextBox、ToolStripComboBox 等也不会) .
递归函数可以是一个 iterator which returns an IEnumerable(Of ToolStripMenuItem)
,它产生在 for each
循环中找到的每个项目。
调用主方法,例如:
► 将 Option Strict
、Option Explicit
和 Option Infer
设置为 On
Dim cmsItems As Dictionary(Of String, String) = GetAllContextMenuItems(contextMenuStrip1)
Imports System.Linq
Private Function GetAllContextMenuItems(contextMenu As ContextMenuStrip) As Dictionary(Of String, String)
If contextMenu Is Nothing OrElse (Not contextMenu.HasChildren) Then Return Nothing
Dim dict = New Dictionary(Of String, String)
For Each item As ToolStripMenuItem In contextMenu.Items.OfType(Of ToolStripMenuItem)
dict.Add(item.Name, item.Text)
For Each subItem In GetSubMenuItems(item)
dict.Add(subItem.Name, subItem.Text)
Next
Next
Return dict
End Function
Private Iterator Function GetSubMenuItems(parent As ToolStripMenuItem) As IEnumerable(Of ToolStripMenuItem)
For Each item As ToolStripMenuItem In parent.DropDownItems.OfType(Of ToolStripMenuItem)
If item.HasDropDownItems Then
For Each subItem As ToolStripMenuItem In GetSubMenuItems(item)
Yield subItem
Next
Else
Yield item
End If
Next
End Function