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&amp;t" visible="-1" id="21" />
  <control caption="&amp;Copy" visible="-1" id="19" />
  <control caption="&amp;Paste" visible="-1" id="22" />
  <control caption="Paste &amp;Special..." visible="-1" id="21437" />
  <control caption="&amp;Paste Table" visible="-1" id="3624" />
  <control caption="&amp;Insert..." visible="-1" id="3181" />
  <control caption="&amp;Delete..." visible="-1" id="292" />
  <control caption="Clear Co&amp;ntents" visible="-1" id="3125" />
  <control caption="Sp&amp;arklines" visible="0" id="31623" />
  <control caption="Filt&amp;er" visible="-1" id="31402" />
  <control caption="S&amp;ort" visible="-1" id="31435" />
  <control caption="Insert Co&amp;mment" visible="-1" id="2031" />
  <control caption="Delete Co&amp;mment" visible="0" id="1592" />
  <control caption="Sh&amp;ow/Hide Comments" visible="0" id="1593" />
  <control caption="&amp;Format Cells..." visible="-1" id="855" />
  <control caption="Pic&amp;k From Drop-down List..." visible="-1" id="1966" />
  <control caption="&amp;Show Phonetic Field" visible="0" id="1614" />
  <control caption="Define N&amp;ame..." visible="-1" id="13380" />
  <control caption="&amp;Hyperlink..." visible="-1" id="1576" />
  <control caption="Edit &amp;Hyperlink..." visible="0" id="1577" />
  <control caption="&amp;Open Hyperlink" visible="0" id="1015" />
  <control caption="&amp;Remove Hyperlink" visible="0" id="3626" />
  <control caption="E&amp;xpand to detail" visible="0" id="11299" />
  <control caption="Additional Act&amp;ions" visible="0" id="31595" />
  <control caption="F&amp;ull Screen" visible="0" id="178" />
  <control caption="&amp;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本身(他们有 CaptionsaccDescriptionTooltipTextaccName 等,但没有像 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 的更多信息: