Marvin's Blog【程式人生】

Ability will never catch up with the demand for it

05 Jan 2021

MS Office RibbonX的CustomUI

微软Office采用的是Ribbon风格的界面。Ribbon具有Extensibility,也就是RibbonX,可以允许用户对界面进行自定义。这个功能叫做CustomUI。具体实现是通过XML对Ribbon进行定制。由于Office套件已经改用OpenXML作为存储格式。用于CustomUI的XML可以作为OpenXML的一部分存在文档里面,让不同的文档有不同的界面呈现。

文章搜罗

Overview of the Office Fluent ribbon (2019)

Ribbon具有Extensibility,可以允许使用XML来扩展用户界面。这样的好处之一是可以避免传统的通过复杂的基于CommandBars对象模型的add-in来实现对UI的修改。

下列方法可以实现应用级别的自定义:

  • 使用托管和非托管代码实现的COM插件
  • 使用VBA作成的针对特定应用的插件,形如.ppam或者.xlam
  • 通过Word的模板(.dotm)所实现的UI更改。

文档级别的自定义可以包含在以下OpenXML格式中:docx,docm,xlsx,xlsm,pptx,pptm。这种情况下,需要将CustomUI的XML先准备好,然后以某种方式融合到目标OpenXML文档中。如果CustomUI中有回调函数,可能需要在文档中增加相应的VBA代码(或者COM插件中的C#代码)。

下面是回调的一个例子:

<button id="myButton" onAction="MyButtonOnAction" />
public void MyButtonOnAction (IRibbonControl control) 
   { 
      if (control.Id=="myButton") 
      { 
         System.Windows.Forms.MessageBox.Show("Button clicked!"); 
      } 
   } 

在Office2007之前,需要通过VBA代码来调配CommandBars对象模型才能自定义UI。

下面是CustomUI XML的一个例子:

<customUI xmlns="http://schemas.microsoft.com/office/2006/01/customui"> 
  <ribbon> 
    <tabs> 
      <tab idMso="TabHome"> 
        <group idMso="GroupFont" visible="false" /> 
      </tab> 
      <tab id="CustomTab" label="My Tab"> 
        <group id="SampleGroup" label="Sample Group"> 
          <toggleButton id="ToggleButton1" size="large" label="Large Toggle Button" getPressed="MyToggleMacro"  /> 
          <checkBox id="CheckBox1" label="A CheckBox" screentip="This is a check box" onAction="MyCheckboxMacro" /> 
          <editBox id="EditBox1" getText="MyTextMacro" label="My EditBox" onChange="MyEditBoxMacro"/> 
          <comboBox id="Combo1" label="My ComboBox" onChange="MyComboBoxMacro"> 
            <item id="Zip1" label="33455" /> 
            <item id="Zip2" label="81611" /> 
            <item id="Zip3" label="31561" /> 
          </comboBox> 
          <advanced> 
            <button id="Launcher1" screentip="My Launcher" onAction="MyLauncherMacro" /> 
          </advanced> 
        </group> 
        <group id="MyGroup" label="My Group" > 
          <button id="Button" label="My Large Button" size="large" onAction="MyButtonMacro" /> 
          <button id="Button2" label="My Normal Button" size="normal" onAction="MyOtherButtonMacro" /> 
        </group > 
      </tab> 
    </tabs> 
  </ribbon> 
</customUI> 

Customize the Office Fluent ribbon by using an Open XML formats file中也能看到相应的例子。

Customizing Context Menus in Office 2010

Office 2010开始,可以通过RibbonX来定制场景菜单(Context Menu)。支持以下功能:

  • 添加内置的或者自定的控件
    • 在菜单的任何位置
    • 在任何子菜单
    • 甚至可以添加子菜单
  • 隐藏某控件
  • 添加分隔线
  • 通过dynamicMenu控件动态修改菜单
  • 动态添加自定义的galleries

不支持以下功能:

  • 有限控件(比如combo box或者inputs)无法添加到菜单
  • 改变内置菜单控件的icon和label
  • 调整内置菜单以及子菜单的控件位置
  • 动态向内置菜单中添加内容

下列控件可以出现在菜单中:

  • control
  • button
  • checkBox
  • dynamicMenu
  • gallery
  • menu
  • menuSeparator
  • splitButton
  • toggleButton

Word中可以直接插入Custom UI Part。Add XML markup to the Word 2010 document展示了一个例子。

另有一篇文章,专门针对Excel:Customizing Context Menus in All Versions of Microsoft Excel

Introduction to the Office 2010 Backstage View for Developers

原来点击File时候跳出的视图叫做Backstage View,也可以通过CustomUI进行更新的。

Using a Microsoft Office Custom Ribbon UI editor

这篇文章写得挺好的。

macOS版的Office 15.17以后也可以支持Ribbon扩展。

文章中列举了三个CustomUI XML编辑器:

  • RibbonX Visual Designer 2010 – an Office Add-in
  • RibbonCreator 2016 – Shareware
  • Custom UI Editor for Microsoft Office – Free (this is a file download link)

此外还有Fernando Andreu创作的Office RibbonX Editor

Improved Custom UI Editor

其他参考

工具和资源

示例

在Word中创建一个右键菜单项:

<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
   <contextMenus>
      <contextMenu idMso="ContextMenuText">
         <button idMso="FontDialog" visible="false" />
         <toggleButton id="MyToggle" label="My Toggle Button" />
      </contextMenu>
   </contextMenus>
</customUI>

在PowerPoint中创建一个右键菜单项:

<?xml version="1.0" encoding="utf-8"?>
<customUI xmlns="http://schemas.microsoft.com/office/2009/07/customui">
  <contextMenus>
    <contextMenu idMso="ContextMenuFrame"> 
      <button id="idCustomItem" label="My custom menu item" onAction="CustomHandler" /> 
    </contextMenu>
  </contextMenus>
</customUI>

(此处是底线)