Excel:XML - ContextMenuListRange 的 ContextMenu 编辑
Excel: XML - ContextMenu editing for ContextMenuListRange
我正在尝试为 Excel 隐藏 <contextMenu idMso="ContextMenuListRange">
的元素。我的问题是我无法在任何地方找到 child idMso
。 (甚至在 Office UI 帮助文件中也不行)。
我一直在猜测,这让我一无所获。任何人都知道我在哪里可以找到这些信息?最有帮助的是查看驱动此上下文菜单的 XML
。
到目前为止我的猜测:
<contextMenus>
<contextMenu idMso="ContextMenuListRange">
<button visible = "false" idMso = "Cut"/>
<button visible = "false" idMso = "Copy"/>
<button visible = "false" idMso = "InsertComment"/> <!--Not correct-->
<button visible = "false" idMso = "FormatCells"/> <!--Not correct-->
<button visible = "false" idMso = "Hyperlink"/> <!--Not correct-->
</contextMenu>
</contextMenus>
对于此类任务,您应该使用 RibbonX Visual Designer。
您可以查看“Excel 2016 Power Programming with VBA”一书的 this 章节以获得更多信息信息。
您可以对“插入评论”控件使用如下内容:
Application.CommandBars("Cell").FindControl(ID:=2031).Enabled = False
Alistair Mcmillan 在 this blog post 处有代码,它将为您提供命令所需的完整 ID 列表。我链接到它但没有重新 posting 因为它不是我的 post.
下面是一些 VBA 代码,用于遍历控件列表并输出它们的名称(菜单文本)和 ID。从这里您可以遍历控件并按名称或 ID 启用/禁用。
' Delete the custom controls with the Tag : My_Cell_Control_Tag.
For Each ctrl In ContextMenu.Controls
If ctrl.Tag = "My_Cell_Control_Tag" Then
ctrl.Delete
End If
Next ctrl
列出每个控件的完整代码,您可以在循环中做一些事情来删除除您想要保留的控件之外的每个控件。
Sub ControlList()
Dim ContextMenu As CommandBar
Dim ctrl As CommandBarControl
' Set ContextMenu to the Cell context menu.
Set ContextMenu = Application.CommandBars("Cell")
Set xmlControl = CreateObject("MSXML2.DOMDocument")
xmlControl.LoadXML ("<xml/>")
For Each ctrl In ContextMenu.Controls
Set ndChild = xmlControl.createNode(1, "control", "")
' Call ndChild.setAttribute("tooltip", ctrl.TooltipText)
Call ndChild.setAttribute("caption", ctrl.Caption)
Call ndChild.setAttribute("visible", ctrl.Visible)
Call ndChild.setAttribute("id", ctrl.ID)
Set ndChild = xmlControl.DocumentElement.appendChild(ndChild)
Next ctrl
' xmlControl.Save ("c:\temp\controllist.xml")
MsgBox xmlControl.xml
End Sub
<xml>
<control caption="Cu&t" visible="-1" id="21" />
<control caption="&Copy" visible="-1" id="19" />
<control caption="&Paste" visible="-1" id="22" />
<control caption="Paste &Special..." visible="-1" id="21437" />
<control caption="&Paste Table" visible="-1" id="3624" />
<control caption="&Insert..." visible="-1" id="3181" />
<control caption="&Delete..." visible="-1" id="292" />
<control caption="Clear Co&ntents" visible="-1" id="3125" />
<control caption="Sp&arklines" visible="0" id="31623" />
<control caption="Filt&er" visible="-1" id="31402" />
<control caption="S&ort" visible="-1" id="31435" />
<control caption="Insert Co&mment" visible="-1" id="2031" />
<control caption="Delete Co&mment" visible="0" id="1592" />
<control caption="Sh&ow/Hide Comments" visible="0" id="1593" />
<control caption="&Format Cells..." visible="-1" id="855" />
<control caption="Pic&k From Drop-down List..." visible="-1" id="1966" />
<control caption="&Show Phonetic Field" visible="0" id="1614" />
<control caption="Define N&ame..." visible="-1" id="13380" />
<control caption="&Hyperlink..." visible="-1" id="1576" />
<control caption="Edit &Hyperlink..." visible="0" id="1577" />
<control caption="&Open Hyperlink" visible="0" id="1015" />
<control caption="&Remove Hyperlink" visible="0" id="3626" />
<control caption="E&xpand to detail" visible="0" id="11299" />
<control caption="Additional Act&ions" visible="0" id="31595" />
<control caption="F&ull Screen" visible="0" id="178" />
<control caption="&Additional Actions" visible="-1" id="22577" />
</xml>
乍一看,我以为我很快就会得到 idMSO
的列表,但结果并没有那么简单。
手动 RibbonX 设计的文档是有限的 -- 因为 Microsoft 推荐(并且 supported) method is with Visual Studio 2017 (which free 个人开发者)。
除此之外,最好的办法可能是坚持使用 VBA。
如果你没试过,还有:
ContextMenus Add-In for Office 2010
A com add-in from Microsoft adds idMso
name to the bottom of every Context menu. A simple way to determine the idMso
for use it in the RibbonX. (Requires .NET Framework
version 3.5)
Download Microsoft ContextMenusaddin from Ron de Bruin's site here.
More info including Downloadable Dynamic menu Example files here.
I couldn't get it working since it's specific to 2010 but it sounds promising.
除此之外,最好的办法可能是坚持使用 VBA。
我拼凑了一个 Excel 函数来列出 174 个命令栏中的所有 ~1600 个控件 - 但它也可以很容易地适应修改工具栏。
例如,此语句禁用上下文菜单上的 Insert Comments
命令:(和 =TRUE
到 re-enable)
Application.CommandBars("Cell").FindControl(ID:=2031).Enabled = False
...以及 get
设置 属性 值的示例:
Debug.Print Application.CommandBars("Cell").FindControl(ID:=2031).Caption
...或者,相同的结果,但使用 CallByName 因此 属性 名称可以来自变量(或直接解析):
Debug.Print CallByName(Application.CommandBars("Cell").Controls(cIndex), "Caption", VbGet)
CommandBarControls
没有 Name
本身(他们有 Captions
、accDescription
、TooltipText
和 accName
等,但没有像 Commandbar
[=114 这样的常规 Name
=] do) 所以引用它们的最佳方式是 ID
。
示例输出:
Index Id accState Caption Enabled
1 21 1048576 Cu&t TRUE
2 19 1048576 &Copy TRUE
3 22 1 &Paste FALSE
4 21437 1 Paste &Special... FALSE
5 3624 1 &Paste Table FALSE
6 25536 1048576 Smart &Lookup TRUE
7 32736 32768 Tran&slate TRUE
8 32713 32768 &Linked Entity TRUE
9 3181 1048576 &Insert... TRUE
10 3181 32768 &Insert... TRUE
11 292 1048576 &Delete... TRUE
12 3125 1048576 Clear Co&ntents TRUE
13 24508 1048576 &Quick Analysis TRUE
14 31623 32768 Sp&arklines TRUE
15 31402 1048576 Filt&er TRUE
16 31435 1048576 S&ort TRUE
17 2031 1048576 Insert Co&mment TRUE
18 1592 32769 Delete Co&mment FALSE
19 1593 32769 Sh&ow/Hide Comments FALSE
20 855 1048576 &Format Cells... TRUE
21 1966 1048576 Pic&k From Drop-down List... TRUE
22 1614 32768 &Show Phonetic Field TRUE
23 13380 1048576 Define N&ame... TRUE
24 1576 32768 &Hyperlink... TRUE
25 1577 32769 Edit &Hyperlink... FALSE
26 1015 32769 &Open Hyperlink FALSE
27 3626 32769 &Remove Hyperlink FALSE
您提到的错误是因为每个 CommandBar
不一定都有每个 Property
- 但 Resume Next
会解决这个问题。由于 Excel 的每个版本都有轻微的 CommandBar
差异,因此最好在您的计算机上生成列表以说明我们版本之间的差异。
Option Explicit
Sub listContextMenuCommands()
Const wkshtName = "Commands2"
Const startRow = 1
Dim commandbarIndex As Integer
Dim cIndex As Integer, sht As Worksheet, cb As CommandBar
Dim cellCmd As Variant, testVar As Variant
Dim col As Integer, rw As Integer
'list of selected properties to report upon
cellCmd = Array("accChild", "accChildCount", "accDefaultAction", "accDescription", "accDoDefaultAction", _
"accFocus", "accHelp", "accHelpTopic", "accHitTest", "accKeyboardShortcut", "accLocation", "accName", _
"accNavigate", "accParent", "accRole", "accSelect", "accSelection", "accState", "accValue", "AdaptiveMenu", _
"AddRef", "BeginGroup", "BuiltIn", "Caption", "Context", "Controls", "Creator", "DescriptionText", _
"Enabled", "GetIDsOfNames", "GetTypeInfo", "GetTypeInfoCount", "Height", "HelpContextID", "Id", "Index", _
"InstanceId", "InstanceIdPtr)", "Invoke", "IsPriorityDropped", "Left", "Name", "NameLocal", "OLEUsage", _
"OnAction", "Parameter", "Parent", "Position", "Priority", "Protection", "QueryInterface", "Release", _
"RowIndex", "Tag", "TooltipText", "Top", "Type", "Visible", "Width")
'prepare worksheet for output
Set sht = Sheets(wkshtName)
rw = startRow
If MsgBox("Existing data will be cleared from worksheet '" & wkshtName & "'.", vbOKCancel, "Erase data?") <> vbOK Then Exit Sub
sht.Cells.ClearContents 'delete all values
sht.Activate
'populate headings
sht.Cells(rw, 1) = "CommandBar"
sht.Range(Cells(rw, 2), Cells(rw, UBound(cellCmd) + 1)) = cellCmd 'dump array of headings into range
On Error Resume Next 'errors will be generated for properties unavailable for certain commands
For commandbarIndex = 1 To Application.CommandBars.Count 'enumerate all command bars
Set cb = Application.CommandBars(commandbarIndex) ' refer to commandbar by name (like "Cell"=context menu) or by Index #
For cIndex = 1 To cb.Controls.Count ' enumerate all controls on commandbar
testVar = CallByName(cb.Controls(cIndex), "Index", VbGet)
If Err Then 'error: control doesn't exist
Debug.Print "No cIndex : Commandbar: #" & cb.Index & " '" & cb.Name & "' Ctl# " & cIndex
Err.Clear 'clear error
GoTo nextCtl 'skip this command
End If
rw = rw + 1 'next row
sht.Cells(rw, 1) = cb.Name 'title of command bar in first column
For col = 1 To UBound(cellCmd) 'populate each [col] for this [rw]
'use "CallByName" so we can specify control name with variables (array)
sht.Cells(rw, col + 1) = CallByName(cb.Controls(cIndex), cellCmd(col - 1), VbGet)
If Err Then 'catch error
sht.Cells(rw, col + 1) = "{N/A}" 'property not available for this control
Err.Clear 'clear error
End If
Next col 'next column
Application.StatusBar = "Listing Commands: " & Format(commandbarIndex / Application.CommandBars.Count, "0.0%")
nextCtl:
Next cIndex 'next control
DoEvents
Next commandbarIndex 'next commandbar
sht.[a1].Select
sht.Columns.AutoFit
Debug.Print "Finished " & Application.CommandBars.Count & " Command Bars, " & rw - startRow & " commands."
End Sub
代码有点混乱且效率低下,因此它可能会在获取 ~100k 属性时挂起片刻。您只需要在常量中指定一个空白工作表名称,但您将希望获得相关命令栏信息的完整列表。
来自 MSDN 的更多信息:
我正在尝试为 Excel 隐藏 <contextMenu idMso="ContextMenuListRange">
的元素。我的问题是我无法在任何地方找到 child idMso
。 (甚至在 Office UI 帮助文件中也不行)。
我一直在猜测,这让我一无所获。任何人都知道我在哪里可以找到这些信息?最有帮助的是查看驱动此上下文菜单的 XML
。
到目前为止我的猜测:
<contextMenus>
<contextMenu idMso="ContextMenuListRange">
<button visible = "false" idMso = "Cut"/>
<button visible = "false" idMso = "Copy"/>
<button visible = "false" idMso = "InsertComment"/> <!--Not correct-->
<button visible = "false" idMso = "FormatCells"/> <!--Not correct-->
<button visible = "false" idMso = "Hyperlink"/> <!--Not correct-->
</contextMenu>
</contextMenus>
对于此类任务,您应该使用 RibbonX Visual Designer。
您可以查看“Excel 2016 Power Programming with VBA”一书的 this 章节以获得更多信息信息。
您可以对“插入评论”控件使用如下内容:
Application.CommandBars("Cell").FindControl(ID:=2031).Enabled = False
Alistair Mcmillan 在 this blog post 处有代码,它将为您提供命令所需的完整 ID 列表。我链接到它但没有重新 posting 因为它不是我的 post.
下面是一些 VBA 代码,用于遍历控件列表并输出它们的名称(菜单文本)和 ID。从这里您可以遍历控件并按名称或 ID 启用/禁用。
' Delete the custom controls with the Tag : My_Cell_Control_Tag.
For Each ctrl In ContextMenu.Controls
If ctrl.Tag = "My_Cell_Control_Tag" Then
ctrl.Delete
End If
Next ctrl
列出每个控件的完整代码,您可以在循环中做一些事情来删除除您想要保留的控件之外的每个控件。
Sub ControlList()
Dim ContextMenu As CommandBar
Dim ctrl As CommandBarControl
' Set ContextMenu to the Cell context menu.
Set ContextMenu = Application.CommandBars("Cell")
Set xmlControl = CreateObject("MSXML2.DOMDocument")
xmlControl.LoadXML ("<xml/>")
For Each ctrl In ContextMenu.Controls
Set ndChild = xmlControl.createNode(1, "control", "")
' Call ndChild.setAttribute("tooltip", ctrl.TooltipText)
Call ndChild.setAttribute("caption", ctrl.Caption)
Call ndChild.setAttribute("visible", ctrl.Visible)
Call ndChild.setAttribute("id", ctrl.ID)
Set ndChild = xmlControl.DocumentElement.appendChild(ndChild)
Next ctrl
' xmlControl.Save ("c:\temp\controllist.xml")
MsgBox xmlControl.xml
End Sub
<xml>
<control caption="Cu&t" visible="-1" id="21" />
<control caption="&Copy" visible="-1" id="19" />
<control caption="&Paste" visible="-1" id="22" />
<control caption="Paste &Special..." visible="-1" id="21437" />
<control caption="&Paste Table" visible="-1" id="3624" />
<control caption="&Insert..." visible="-1" id="3181" />
<control caption="&Delete..." visible="-1" id="292" />
<control caption="Clear Co&ntents" visible="-1" id="3125" />
<control caption="Sp&arklines" visible="0" id="31623" />
<control caption="Filt&er" visible="-1" id="31402" />
<control caption="S&ort" visible="-1" id="31435" />
<control caption="Insert Co&mment" visible="-1" id="2031" />
<control caption="Delete Co&mment" visible="0" id="1592" />
<control caption="Sh&ow/Hide Comments" visible="0" id="1593" />
<control caption="&Format Cells..." visible="-1" id="855" />
<control caption="Pic&k From Drop-down List..." visible="-1" id="1966" />
<control caption="&Show Phonetic Field" visible="0" id="1614" />
<control caption="Define N&ame..." visible="-1" id="13380" />
<control caption="&Hyperlink..." visible="-1" id="1576" />
<control caption="Edit &Hyperlink..." visible="0" id="1577" />
<control caption="&Open Hyperlink" visible="0" id="1015" />
<control caption="&Remove Hyperlink" visible="0" id="3626" />
<control caption="E&xpand to detail" visible="0" id="11299" />
<control caption="Additional Act&ions" visible="0" id="31595" />
<control caption="F&ull Screen" visible="0" id="178" />
<control caption="&Additional Actions" visible="-1" id="22577" />
</xml>
乍一看,我以为我很快就会得到 idMSO
的列表,但结果并没有那么简单。
手动 RibbonX 设计的文档是有限的 -- 因为 Microsoft 推荐(并且 supported) method is with Visual Studio 2017 (which free 个人开发者)。
除此之外,最好的办法可能是坚持使用 VBA。
如果你没试过,还有:
ContextMenus Add-In for Office 2010
A com add-in from Microsoft addsidMso
name to the bottom of every Context menu. A simple way to determine theidMso
for use it in the RibbonX. (Requires.NET Framework
version 3.5)
Download Microsoft ContextMenusaddin from Ron de Bruin's site here.
More info including Downloadable Dynamic menu Example files here.
I couldn't get it working since it's specific to 2010 but it sounds promising.
除此之外,最好的办法可能是坚持使用 VBA。
我拼凑了一个 Excel 函数来列出 174 个命令栏中的所有 ~1600 个控件 - 但它也可以很容易地适应修改工具栏。
例如,此语句禁用上下文菜单上的 Insert Comments
命令:(和 =TRUE
到 re-enable)
Application.CommandBars("Cell").FindControl(ID:=2031).Enabled = False
...以及 get
设置 属性 值的示例:
Debug.Print Application.CommandBars("Cell").FindControl(ID:=2031).Caption
...或者,相同的结果,但使用 CallByName 因此 属性 名称可以来自变量(或直接解析):
Debug.Print CallByName(Application.CommandBars("Cell").Controls(cIndex), "Caption", VbGet)
CommandBarControls
没有 Name
本身(他们有 Captions
、accDescription
、TooltipText
和 accName
等,但没有像 Commandbar
[=114 这样的常规 Name
=] do) 所以引用它们的最佳方式是 ID
。
示例输出:
Index Id accState Caption Enabled
1 21 1048576 Cu&t TRUE
2 19 1048576 &Copy TRUE
3 22 1 &Paste FALSE
4 21437 1 Paste &Special... FALSE
5 3624 1 &Paste Table FALSE
6 25536 1048576 Smart &Lookup TRUE
7 32736 32768 Tran&slate TRUE
8 32713 32768 &Linked Entity TRUE
9 3181 1048576 &Insert... TRUE
10 3181 32768 &Insert... TRUE
11 292 1048576 &Delete... TRUE
12 3125 1048576 Clear Co&ntents TRUE
13 24508 1048576 &Quick Analysis TRUE
14 31623 32768 Sp&arklines TRUE
15 31402 1048576 Filt&er TRUE
16 31435 1048576 S&ort TRUE
17 2031 1048576 Insert Co&mment TRUE
18 1592 32769 Delete Co&mment FALSE
19 1593 32769 Sh&ow/Hide Comments FALSE
20 855 1048576 &Format Cells... TRUE
21 1966 1048576 Pic&k From Drop-down List... TRUE
22 1614 32768 &Show Phonetic Field TRUE
23 13380 1048576 Define N&ame... TRUE
24 1576 32768 &Hyperlink... TRUE
25 1577 32769 Edit &Hyperlink... FALSE
26 1015 32769 &Open Hyperlink FALSE
27 3626 32769 &Remove Hyperlink FALSE
您提到的错误是因为每个 CommandBar
不一定都有每个 Property
- 但 Resume Next
会解决这个问题。由于 Excel 的每个版本都有轻微的 CommandBar
差异,因此最好在您的计算机上生成列表以说明我们版本之间的差异。
Option Explicit
Sub listContextMenuCommands()
Const wkshtName = "Commands2"
Const startRow = 1
Dim commandbarIndex As Integer
Dim cIndex As Integer, sht As Worksheet, cb As CommandBar
Dim cellCmd As Variant, testVar As Variant
Dim col As Integer, rw As Integer
'list of selected properties to report upon
cellCmd = Array("accChild", "accChildCount", "accDefaultAction", "accDescription", "accDoDefaultAction", _
"accFocus", "accHelp", "accHelpTopic", "accHitTest", "accKeyboardShortcut", "accLocation", "accName", _
"accNavigate", "accParent", "accRole", "accSelect", "accSelection", "accState", "accValue", "AdaptiveMenu", _
"AddRef", "BeginGroup", "BuiltIn", "Caption", "Context", "Controls", "Creator", "DescriptionText", _
"Enabled", "GetIDsOfNames", "GetTypeInfo", "GetTypeInfoCount", "Height", "HelpContextID", "Id", "Index", _
"InstanceId", "InstanceIdPtr)", "Invoke", "IsPriorityDropped", "Left", "Name", "NameLocal", "OLEUsage", _
"OnAction", "Parameter", "Parent", "Position", "Priority", "Protection", "QueryInterface", "Release", _
"RowIndex", "Tag", "TooltipText", "Top", "Type", "Visible", "Width")
'prepare worksheet for output
Set sht = Sheets(wkshtName)
rw = startRow
If MsgBox("Existing data will be cleared from worksheet '" & wkshtName & "'.", vbOKCancel, "Erase data?") <> vbOK Then Exit Sub
sht.Cells.ClearContents 'delete all values
sht.Activate
'populate headings
sht.Cells(rw, 1) = "CommandBar"
sht.Range(Cells(rw, 2), Cells(rw, UBound(cellCmd) + 1)) = cellCmd 'dump array of headings into range
On Error Resume Next 'errors will be generated for properties unavailable for certain commands
For commandbarIndex = 1 To Application.CommandBars.Count 'enumerate all command bars
Set cb = Application.CommandBars(commandbarIndex) ' refer to commandbar by name (like "Cell"=context menu) or by Index #
For cIndex = 1 To cb.Controls.Count ' enumerate all controls on commandbar
testVar = CallByName(cb.Controls(cIndex), "Index", VbGet)
If Err Then 'error: control doesn't exist
Debug.Print "No cIndex : Commandbar: #" & cb.Index & " '" & cb.Name & "' Ctl# " & cIndex
Err.Clear 'clear error
GoTo nextCtl 'skip this command
End If
rw = rw + 1 'next row
sht.Cells(rw, 1) = cb.Name 'title of command bar in first column
For col = 1 To UBound(cellCmd) 'populate each [col] for this [rw]
'use "CallByName" so we can specify control name with variables (array)
sht.Cells(rw, col + 1) = CallByName(cb.Controls(cIndex), cellCmd(col - 1), VbGet)
If Err Then 'catch error
sht.Cells(rw, col + 1) = "{N/A}" 'property not available for this control
Err.Clear 'clear error
End If
Next col 'next column
Application.StatusBar = "Listing Commands: " & Format(commandbarIndex / Application.CommandBars.Count, "0.0%")
nextCtl:
Next cIndex 'next control
DoEvents
Next commandbarIndex 'next commandbar
sht.[a1].Select
sht.Columns.AutoFit
Debug.Print "Finished " & Application.CommandBars.Count & " Command Bars, " & rw - startRow & " commands."
End Sub
代码有点混乱且效率低下,因此它可能会在获取 ~100k 属性时挂起片刻。您只需要在常量中指定一个空白工作表名称,但您将希望获得相关命令栏信息的完整列表。