存档在 ‘Ribbon/RibbonX’ 分类中.

使用WPF创建Office 2007功能区风格的自定义面板

Technorati 标签: ,,,

WPF,Windows Presentation Foundation,是Microsoft在.NET 3.0中引入的新组件,提供了表现层技术基础,用于统一处理用户界面和可视化元素。WPF的出现,使得用户开发具有震撼力的用户界面体验更加轻松和可能。同时,WPF是基于XAML(可扩展应用程序标记语言)来定义界面元素的。

下面是《Windows Presentation Foundation Unleashed》一书中使用WPF技术创建仿Office 2007 功能区的自定义面板的示例,所实现的结果如下图所示:

getRibbonCustomPanelpic

同时,记录下部分代码:

   1: Imports System
   2: Imports System.Windows
   3: Imports System.Windows.Controls
   4:  
   5: Namespace CustomPanel
   6:     Public Class RibbonPanel
   7:      Inherits Panel
   8:         Protected Overrides Function MeasureOverride(ByVal availableSize As Size) As Size
   9:             If Children.Count < 1 Then
  10:                  Return New Size(0, 0)
  11:             End If
  12:  
  13:             ‘ Ask the first child for its desired size, given unlimited space
  14:             Dim firstChild As UIElement =  Children(0) 
  15:             firstChild.Measure(New Size(Double.PositiveInfinity,Double.PositiveInfinity))
  16:  
  17:             ‘ If there’s only one child, this panel would like to be the exact same size
  18:             If Children.Count < 2 Then
  19:                  Return firstChild.DesiredSize
  20:             End If
  21:  
  22:             ‘ If not, calculate the desired width based on all children
  23:             Dim numRows As Double =  Math.Ceiling((Children.Count - 1) / 3d) 
  24:             Dim maxWidthForEachRemainingChild As Double =  0 
  25:  
  26:             Dim i As Integer
  27:             For  i = 1 To  Children.Count- 1  Step  i + 1
  28:                 ‘ Ask each child for its desired size, given unlimited space
  29:                 Dim child As UIElement =  Children(i) 
  30:                 child.Measure(New Size(Double.PositiveInfinity,Double.PositiveInfinity))
  31:  
  32:                 ‘ Keep track of the maximum width
  33:                 maxWidthForEachRemainingChild = Math.Max(child.DesiredSize.Width, maxWidthForEachRemainingChild)
  34:             Next
  35:  
  36:             Return New Size(
  37:                 firstChild.DesiredSize.Width + maxWidthForEachRemainingChild * numRows, ‘ total width
  38:                 Dim ‘ height = desired height of the first child As firstChild.DesiredSize.Height)
  39:         End Function
  40:  
  41:         Protected Overrides Function ArrangeOverride(ByVal finalSize As Size) As Size
  42:             If Children.Count < 1 Then
  43:                  Return finalSize
  44:             End If
  45:  
  46:             ‘ Give the first child its desired width but the height of the panel
  47:             Dim firstChild As UIElement =  Children(0) 
  48:             Dim childOrigin As Point =  New Point(0,0) 
  49:             Dim firstChildSize As Size =  New Size(firstChild.DesiredSize.Width,finalSize.Height) 
  50:             firstChild.Arrange(New Rect(childOrigin,firstChildSize))
  51:  
  52:             If Children.Count < 2 Then
  53:                  Return finalSize
  54:             End If
  55:  
  56:             ‘ Determine the size for all the remaining children
  57:             Dim numRows As Double =  Math.Ceiling((Children.Count - 1) / 3d) 
  58:             Dim childSize As Size =  New Size((finalSize.Width - firstChildSize.Width) / numRows,finalSize.Height / 3) 
  59:             childOrigin.X += firstChildSize.Width
  60:  
  61:             Dim i As Integer
  62:             For  i = 1 To  Children.Count- 1  Step  i + 1
  63:                 Dim child As UIElement =  Children(i) 
  64:                 child.Arrange(New Rect(childOrigin,childSize))
  65:  
  66:                 If i % 3 = 0 Then
  67:                     ‘ Start a new column
  68:                     childOrigin.X += childSize.Width
  69:                     childOrigin.Y = 0
  70:                 Else 
  71:                     childOrigin.Y += childSize.Height
  72:                 End If
  73:             Next
  74:  
  75:             ‘ Fill all the space given
  76:             Return finalSize
  77:         End Function
  78:     End Class
  79: End Namespace
标签: 没有标签

在Excel 2007的功能区中添加中文选项卡和控件

下面是Qu朋友在本站中的留言:
谢谢你这么专业地工作。能否做一个EXCEL2007下的中文菜单样板?我按您和网上其它人介绍的方法(无论是ZIP方式、还是用UI编辑器),总是无法正常。

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
我想,他的意思是在Excel 2007的功能区中添加中文选项卡或者控件,例如自定义的组、按钮等,不过,选项卡或这些控件的标签都应该是中文的。下面我来演示具体的步骤。
在开始之前,先声明Office 2007 CustomUI Editor并不支持中文,因此不能使用这个方便的工具来定制Ribbon,只能使用修改Office 2007文件格式的方法来解决了。
步骤1 在桌面上创建一个名为customUI的文件夹。
步骤2 打开记事本,并在其中输入下面的XML代码:
<customUI xmlns=”http://schemas.microsoft.com/office/2006/01/customui“>
  <ribbon>
    <tabs>
      <tab id=”rxtabCustom”
           label=”我自已的选项卡”
           insertBeforeMso=”TabHome”>
          <group idMso=”GroupFont”/>
          <group idMso=”GroupZoom”/>
          <group id=”myGroup” label=”我的组”>
              <button id=”b1″
                      imageMso=”HyperlinkInsert”
                      size=”large”
                      label=”启动网站”
                      onAction=”surf”/>
              <button id=”b2″
                      imageMso=”HappyFace”
                      label=”微笑图标”
                      onAction=”smile”/>
              <button id=”b3″
                      imageMso=”FormatPainter”
                      label=”格式刷图标”
                      onAction=”paint”/>
              <button id=”b4″
                      imageMso=”AutoFilterClassic”
                      label=”筛选图标”
                      onAction=”filter”/>
           </group>
     </tab>
   </tabs>
  </ribbon>
</customUI>
该XML文件在Excel的“开始”选项卡前创建了一个名为“我自已的选项卡”的选项卡,并添加了三个组,前两个为Excel内置的组“字体”和“显示比例”,第三个为名为“我的组”的自定义组,其中包括四个自定义的按钮“启动网站”、“微笑图标”、“格式刷图标”和“筛选图标”,并分别定义了onAction属性。
步骤3 将该文件命名为customUI并以.xml为扩展名保存在customUI文件夹中,并关闭该文件。在保存时注意选择“编码”下拉框中的编码为UTF-8,如下图所示。
SaveAsUTF8Format
步骤4 在桌面上新建一个启用宏的Excel文件,并命名为MyCustomUI.xlsm。因为在自定义的XML中,包含了产生回调的onAction属性,所以创建的Excel文件需要启用宏。
步骤5 在MyCustomUI.xlsm中,按Alt+F11组合键打开VBE,并插入一个标准模块,添加下面的代码供回调使用:
Option Explicit‘Callback for b1 onAction
Sub surf(control As IRibbonControl)
    ActiveWorkbook.FollowHyperlink _
      Address:=”http://www.excelperfect.com”, _
      NewWindow:=True
End Sub
‘Callback for b2 onAction
Sub smile(control As IRibbonControl)
    MsgBox “您单击了微笑图标!呵呵…”
End Sub
‘Callback for b3 onAction
Sub paint(control As IRibbonControl)
    MsgBox “您单击了格式刷图标!”
End Sub
‘Callback for b4 onAction
Sub filter(control As IRibbonControl)
    MsgBox “您单击了筛选图标!”
End Sub

步骤6 关闭工作簿MyCustomUI.xlsm。
步骤7 在MyCustomUI.xlsm图标上单击右键,选择“重命名”,在文件名后添加“.zip”扩展名,使其变为一个压缩文件。如下图所示。
changeextendnameforzip
步骤8 双击该压缩文件,打开压缩包,将customUI文件夹拖到该压缩包中,如下图所示。
customuitozip
步骤9 将压缩包中的_rels文件夹拖至桌面。
步骤10 打开桌面中的_rels文件夹,然后用记事本打开其中的.rels文件,如下图所示。
relsfile
步骤11 在.rels文件的最后</Relationships>一个之前,添加下面的XML:
<Relationship Id=”customUIRelID” Type=”http://schemas.microsoft.com/office/2006/relationships/ui/extensibility” Target=”customUI/customUI.xml”/>
步骤12 保存该.rels文件并关闭。
步骤13 将修改后的_rels文件夹拖回MyCustomUI压缩包中。如果出现提示,则选择是,覆盖原文件。关闭压缩包。
步骤14 将MyCustomUI.xlsm.zip的.zip扩展名删除。
步骤15 双击MyCustomUI.xlsm文件,打开工作簿,此时在Excel内置选项卡“开始”的前面添加了一个自定义选项卡,在该选项卡中添加了两个内置组和一个自定义组,如下图所示。
MyCustomUIResult1
看看吧,都是中文的,成功!
示例文件下载:http://www.drexcel.cn/article.asp?id=40

标签: 没有标签

在Excel 2007中共享功能区定制

前不久,Baiyssy朋友在本站留言,大致意思是希望在其他计算机上也能使用本机上已定制好的快速访问工具栏。下面简单地提供几种方法。
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
这里介绍三种方法。这些方法各有优缺点,应该根据实际情况选择使用。
方法一:分发已经完成功能区定制的Excel工作簿
即,先在自已的计算机上完成功能区定制,然后将该工作簿分发给其他需要的人使用。
方法二:使用Excel模板
即,将完成功能区定制的工作簿保存为模板,这样,以后需要或者他人需要使用使用同样的功能区定制时,以此模板打开工作簿。
当该模板在用户计算机的Templates文件夹中安装后,只需简单地选择“Office按钮”─—“新建”─—“我的模板”,然后在对话框中双击合适的模板文件。此时以此模板创建一个新的文件而不会覆盖原模板文件。
创建Excel模板文件是简单的,只需选择“Office按钮”─—“另存为”,然后从“保存类型”下拉列表中选择保存的模板类型(包括xltx和xltm),并输入合适的文件名,单击“保存”按钮即可。
在Windows XP中,当前模板文件夹(Templates)的缺省路径为:
C:\Documents And Settings\<用户名>\Application Data\Microsoft\Templates
注意,不要选择“打开”命令来打开模板文件。如果这样做的话,那么所作的更改会保存在模板文件中。
方法三:使用Excel加载项
使用这种方法虽然有点复杂但将更为灵活,并且加载项将代码与数据分离,同时加载项使定制可见且所有文件都能访问。
1、准备好要转换为加载项的工作簿
如果该工作簿不含VBA代码,那么将很简单。如果该工作簿有VBA代码,则需要进行下面的一些操作。
(1)实例化代码引用的工作簿(ThisWorkbook)。如果工作簿的标准模块中,代码含有ThisWorkbook,则需要使用ActiveWorkbook替换。
(2)实例化没有使用Public或Private声明的子过程和函数。若没有这些前缀,则加上。
2、将准备好的工作簿转换为加载项
很简单,选择“Office按钮”─—“另存为”─—“其他格式”,在保存类型中选择“Excel加载宏”并命名,然后单击“保存”按钮。
此时,原来的文件仍然存在,因为加载项只是该文件的副本。
3、安装加载项
要使用加载项,建议将其直接放置在计算机中缺省的Addins文件夹中。在Windows XP中,该文件夹的位置通常位于:
C:\Documents And Settings\<用户名>\Application Data\Microsoft\Addins
注意,不一定非得将加载项放置在该文件夹中,具体情况视您的要求和方便程度而定。
要安装加载项,单击“Office按钮”─—“Excel选项”,在“Excel选项”对话框中,选择“加载项”─—“转到”,打开“加载宏”对话框。如果您的加载项放置在Addins文件夹中,那么在该对话框的列表中将看到该加载项,此时只需选中其前面的复选框。否则,需要单击“浏览”按钮,找到该加载项,然后在对话框中选中其前面的复选框。最终如下图所示。
AddinDialogha
返回到Excel界面后,就可以看到已经创建了该加载项定制的UI。并且,当打开另一个Excel文件时,新的UI也在其中,酷吧!
这说明创建加载项能够使得在文件之间共享定制。
4、卸载和移除加载项
加载项会占用内存,因此影响程序的运行速度。当不再需要加载项时,可以将其卸载。
如上图的对话框,取消该加载项前复选框中的选择,只是简单地使加载项效果不会在Excel界面中出现,但不是真正卸载该加载项,即该加载项仍然装载。要完全卸载该加载项,需要找到该加载项在计算机中的位置,然后删除该文件或将该文件移动到其他位置,然后在Excel中调出上图所示的对话框,单击该加载项前的复选框,此时,会弹出一个警告对话框,如下图所示,单击“是”按钮并关闭Excel。
DeleteAddinDialogha
此时,将卸载该加载项。
5、其他
通过将加载项的IsAddin属性设置为False将使加载项工作簿显示在Excel界面中,此时可以修改该加载项工作簿。

RibbonX:自定义Office 2007功能区——回调(二)

RibbonX:自定义Office 2007功能区
第五章 回调:对自定义UI添加功能的关键-学习笔记

——————————————–
五、组织回调
1、单个的回调处理
当编写XML代码时,可以指定返回回调的多种属性,例如,onAction、getLabel、getVisible、getEnabled,等等。这些属性的每一个都必须处理。下面的示例演示通过组中产生3个按钮的过程,虽然该示例以Word文档为例,但也可以在Excel中使用。
<customUI xmlns=”http://schemas.microsoft.com/office/2006/01/customui“>
    <ribbon>
       <tabs>
            <tab id=”rxtabDemo”
                 label=”My Custom Tab”
                 insertBeforeMso=”TabHome”>
                 <group id=”rxgrpDemo”
                        label=”My Demo Group”>
                     <button id=”rxbtnPaste”
                             label=”My Paste Button”
                             size=”normal”
                             onAction=”rxbtnPaste_click”
                             imageMso=”Paste”
                             tag=”Custom Paste Button”/>
                     <button id=”rxbtnCopy”
                             label=”My Copy Button”
                             size=”normal”
                             onAction=”rxbtnCopy_click”
                             imageMso=”Copy”
                             tag=”Custom Copy Button”/>
                     <button id=”rxbtnCut”
                             label=”My Cut Button”
                             size=”normal”
                             onAction=”rxbtnCut_click”
                             imageMso=”Cut”
                             tag=”Custom Cut Button”/>
                 </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>
每个按钮都有其onAction属性,因此如果企图对按钮添加功能,则必须处理每个属性:
‘Callback for rxbtnPaste onAction
Sub rxbtnPaste_click(control As IRibbonControl)
    MsgBox “您单击了” & control.Tag, vbInformation
End Sub

‘Callback for rxbtnCopy onAction
Sub rxbtnCopy_click(control As IRibbonControl)
    MsgBox “您单击了” & control.Tag, vbInformation
End Sub

‘Callback for rxbtnCut onAction
Sub rxbtnCut_click(control As IRibbonControl)
    MsgBox “您单击了” & control.Tag, vbInformation
End Sub
一种可供选择的方法是一次处理多个属性。
2、使用全局回调处理
(1)全局回调处理能用于一次处理几个控件。如果以标准化方式命名全局处理,那么效果将更好,因为可以立即从单个控件中区分全局控件。
(2)使用全局回调的原因是因为某些指令可能重复,甚至当指令不重复时,对某种控件为某项操作共享相同的属性仍有好处,如onAction属性。此外,如果操作相同,那么过程能组合在单个的回调处理中。
(3)能利用这种优势减少要处理的回调数。
(4)例如,下列对象:tab,group,button,都共享一个通用的属性getLabel。如前所述,当需要对每个控件动态应用值时,不需要在XML代码中为每个控件编写getLabel回调。相反,可以在VBA过程中在单个过程内将共享任务放在一起,而且因为是回调,不需要遍历XML中指定的控件,将自动遍历控件直至所有控件有所需的值。
(5)仍以上节中的示例,在前面的XML代码中修改每个按钮的onAction属性如下:
onAction=”rxshared_click”
将产生单个的回调,用于处理具有onAction属性和共享标签的任何控件。
接着,在VBA中为每个按钮处理该回调,使用下面的一小段代码:
Sub rxshared_click(control As IRibbonControl)
    MsgBox “您单击了” & control.Tag, vbInformation
End Sub
也能使用Select Case语句分开每个按钮并赋予其特定的代码:
Sub rxshared_click(control As IRibbonControl)
Select Case control.ID
    Case “rxbtnPaste”
      ‘为rxbtnPaste按钮的代码
    Case “rxbtnCopy”
      ‘为rxbtnCopy按钮的代码
    Case “rxbtnCut”
     ‘为rxbtnCut按钮的代码
End Select
End Sub
3、在Access中处理回调
在创建定制时,Access在许多方面都是独特的。
在Access中,能够使用VBA或宏处理回调。当使用Word和Excel时,宏通常指VBA指令,而Access中,宏是创建的对象。此外,因为宏有预定义指令,通常仅需一个参数。
(1)使用VBA处理回调
首先,需要引用Office 12 Object Library,否则会出现错误消息。
例如,下面的XML代码为Access中自定义选项卡/组创建一个按钮:
<customUI xmlns=”http://schemas.microsoft.com/office/2006/01/customui“>
    <ribbon>
        <tabs>
            <tab id=”rxtabDemo”
                 label=”My Custom Tab”
                 insertBeforeMso=”TabHomeAccess”>
                 <group id=”rxgrpDemo”
                        label=”My Demo Group”>
                        <button id=”rxbtnReport”
                                label=”My Report Button”
                                size=”large”
                                onAction=”rxbtnReport_click”
                                imageMso=”CreateReport”
                                tag=”Create Report”/>
                 </group>
             </tab>
        </tabs>
    </ribbon>
</customUI>
在工程中添加一个标准模块,并输入下面的代码:
Sub rxbtnReport_click(control As IRibbonControl)
    On Error GoTo Err_Handler
    DoCmd.OpenReport “MyReport”, acViewDesign
    Exit Sub
Err_Handler:
    MsgBox Err.Description, vbCritical, “Err Number:” & Err.Number
End Sub
本例中,单击按钮后将在视图预览模式下打开名为MyReport的报表。
(2)使用宏处理回调
在Access 12中,macro对象是处理回调的另一种方式。
假设希望使用宏处理onAction属性,需要指定onAction属性:
onAction=”rxMacroName.objectName”
其中,rxMacroName指定在Access中创建的宏对象的名称(宏对象自身)。
objectName指在XML代码中创建的对象id(宏对象是宏名称)。
下图将有助于理解:
AccessCallbackUseMacro 
现在首先创建新的选项卡和组并在其中添加按钮:
<button id=”rxbtnPaste”
                                label=”My Paste Button”
                                size=”normal”
                                onAction=”rxsharedMacro.rxbtnPaste”
                                imageMso=”Paste”
                                tag=”Custom Paste Button”/>
                        <button id=”rxbtnCopy”
                                label=”My Copy Button”
                                size=”normal”
                                onAction=”rxsharedMacro.rxbtnCopy”
                                imageMso=”Copy”
                                tag=”Custom Copy Button”/>
                        <button id=”rxbtnCut”
                                label=”My Cut Button”
                                size=”normal”
                                onAction=”rxsharedMacro.rxbtnCut”
                                imageMso=”Cut”
                                tag=”Custom Cut Button”/>
然后,在Access中添加新的宏对象并将其命名为rxsharedMacro。在设计视图中打开宏,并添加三个新的宏指令。每个使用在XML代码中onAction属性的点之后的文本命名。添加宏指令:一个Beep和2个消息框。
单击自定义选项卡中的按钮,出现类似下面的消息框:
AccessCallbackUseMacro1 
六、使UI组件无效
Ribbon的一个重要方面是使Ribbon无效或指定的控件无效。
某些操作仅当使整个Ribbon无效才能执行,而另一些操作只需通过使指定控件无效来完成。
1、无效能处理什么?为什么需要?
IRibbonUI对象包含两个方法:Invalidate和InvalidateControl。
表:IRibbonUI对象模型
方法                        用途
Invalidate()                  为更新而标记整个功能区(顺序标记其中的每个控件)
InvalidateControl(strControlID) 为更新而标记特定的控件(被更新的控件作为字符串传递到方法的参数中)(strControlID)
理解Invalidate方法的关键是该方法使UI中每个控件都无效,意味着强制调用在UI中定义的所有回调。此外,也将导致更新所有控件,而无论其是否有回调。当使Ribbon无效时,在Ribbon中作出调用,在UI中指定的每个过程都将运行。
“刷新”指在打开工程时简单地更新在UI中已经装载的控件;“重新装载”指卸载并重新装载UI中的整个项目。
除非确实需要作用整个Ribbon,更好的选择是在执行期间的指定时刻使单个控件无效,即当需要时仅使该控件无效。
要使整个Ribbon或Ribbon中指定的控件无效,需要设置代表IRibbonUI对象的全局变量,可通过在onLoad属性中指定回调来实现:
<customUI xmlns=”http://schemas.microsoft.com/office/2006/01/customui” onLoad=”rxIRibbonUI_onLoad”>
</customUI>
接下来,编写VBA代码处理在onLoad属性中指定的回调:
Public grxIRibbonUI As IRibbonUI
Sub rxIRibbonUI_onLoad(ribbon As IRibbonUI)
Set grxIRibbonUI=ribbon
End Sub
注意,代表IRibbonUI对象的变量在标准模块的全局声明区中声明,以便于能被工程的其他部分访问。
2、使整个Ribbon无效
(1)创建一个新的Excel文件,并以启用宏的工作簿保存。
(2)使用CustomUI Editor,在工作簿文件中添加XML代码:
<customUI xmlns=”http://schemas.microsoft.com/office/2006/01/customui” onLoad=”rxIRibbonUI_onLoad”>
    <ribbon>
        <tabs>
            <tab id=”rxtabDemo”
                 label=”My Custom Tab”
                 insertBeforeMso=”TabHome”>
                 <group id=”rxgrpDemo”
                        label=”My Demo Group”>
                     <button id=”rxbtn”
                             getLabel=”rxshared_getLabel”
                             size=”normal”
                             onAction=”rxshared_click”
                             imageMso=”FillRight”/>
                     <button id=”rxbtn2″
                             getLabel=”rxshared_getLabel”
                             size=”normal”
                             onAction=”rxshared_click”
                             imageMso=”FillRight”/>
                 </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>
(3)保存并验证代码。
(4)单击“Generate Callbacks”按钮生成回调。
(5)复制回调代码并关闭该文件。
(6)在Excel中打开该工作簿,添加一个标准模块。
(7)粘贴代码到该模块中,并补充代码。
Public grxIRibbonUI As IRibbonUI
Public glngCount1 As Long
Public glngCount2 As Long
‘Callback for customUI.onLoad
Sub rxIRibbonUI_onLoad(ribbon As IRibbonUI)
    Set grxIRibbonUI = ribbon
End Sub

‘Callback for rxbtn onAction
Sub rxshared_click(control As IRibbonControl)
    grxIRibbonUI.Invalidate
End Sub

‘Callback for rxbtn getLabel
Sub rxshared_getLabel(control As IRibbonControl, ByRef returnedVal)
    Select Case control.ID
        Case “rxbtn”
            returnedVal = “功能区无效:” & glngCount1 & “次.”
            glngCount1 = glngCount1 + 1
        Case “rxbtn2″
            returnedVal = “功能区无效:” & glngCount2 & “次.”
            glngCount2 = glngCount2 + 1
    End Select
End Sub
注意,此时单击任一按钮,两个标签均更新,如下图。因为单击按钮时代码使整个Ribbon无效,所以两个控件都无效,共享的getLabel过程为第一个按钮调用一次,又为第二个按钮所调用。
InvalidateRibbon1 
3、使单个控件无效
仍以上面的例子,仅使触发click事件的按钮无效。将共享的click事件和共享的getLabel事件修改如下:
Public grxIRibbonUI As IRibbonUI
Public glngCount1 As Long
Public glngCount2 As Long
‘Callback for customUI.onLoad
Sub rxIRibbonUI_onLoad(ribbon As IRibbonUI)
    Set grxIRibbonUI = ribbon
End Sub

‘Callback for rxbtn onAction
Sub rxshared_click(control As IRibbonControl)
    Select Case control.ID
        Case “rxbtn”
            glngCount1 = glngCount1 + 1
        Case “rxbtn2″
            glngCount2 = glngCount2 + 1
    End Select
    grxIRibbonUI.InvalidateControl (control.ID)
End Sub

‘Callback for rxbtn getLabel
Sub rxshared_getLabel(control As IRibbonControl, ByRef returnedVal)
    Select Case control.ID
        Case “rxbtn”
            returnedVal = “功能区无效:” & glngCount1 & “次.”
        Case “rxbtn2″
            returnedVal = “功能区无效:” & glngCount2 & “次.”
    End Select
End Sub
此时,只会使单击的控件无效,如下图。
InvalidateRibbon2 

RibbonX:自定义Office 2007功能区——回调(一)

RibbonX:自定义Office 2007功能区
第五章 回调:对自定义UI添加功能的关键-学习笔记

—————————————————–
回调,即使定制能够工作的代码。如果没有回调,UI可能看起来是漂亮的,但只是一个漂亮的Ribbon。当然,除了从内置的控件不需要自定义回调外。
下面介绍XML与VBA组合。需要在XML代码中指定回调,然后编写VBA代码来匹配和处理回调。
一、回调是什么,为什么需要回调
回调是子过程和函数,被自定义UI使用,使得定制的UI能够工作。例如,当设置某按钮的onAction属性并装载时,一旦单击该按钮,就产生回调,即在属性中指定的操作。如果没有找到指定的操作,那么回调将失败,因为代码中发生了例外,即在属性中指定的回调在VBA中不存在。
使用自定义UI中的功能时,UI将调用VBA项目,搜寻指定的函数或过程。如果找到,则将其值传回UI;如果没有发现指定的函数或过程,那将产生错误的结果。
有两种主要的方式来创建回调:
(1)直接在VBE的标准模块中输入过程或函数;
(2)使用工具生成过程,例如Office 2007 CustomUI Editor。
使用工具,例如Office 2007 CustomUI Editor的主要优势之一是能返回一个回调签名,也称作subprocedure stub,对于XML代码中每个属性都有一个回调需要处理,接受回调作为值的属性包括onAction、getVisible和getImage。
使用CustomUI Editor还能避免错误,节省时间。
当项目装载且需要访问某些回调并运行,意味着如果回调处理(即响应回调的VBA代码)在该项目中不存在,则将产生错误消息。
二、为动态回调建立文件
为了使用自定义控件工作,文件必须启用宏,否则不能添加或运行VBA代码。
1、捕获IRibbonUI对象
IRibbonUI对象引用Ribbon用户界面。
在VBA中使用的关键之一是使整个Ribbon对象无效(因而能改变Ribbon的某项特征)或者使Ribbon中指定的控件无效(因而能改变该控件的某项特征)。
(1)调整XML来包括onLoad
为了使用IRibbonUI对象,需要在VBA中对其设置。此时,需要对UI的onLoad属性指定值,这能通过为onLoad属性指定回调来实现。
<customUI xmlns=”http://schemas.microsoft.com/office/2006/01/customui” onLoad=”rxIRibbonUI_onLoad”>
因为onLoad属性的值是一个回调,所以需要在VBA代码中对其进行处理。接着,使得在工程中能够使用IRibbonUI对象。
(2)创建VBA代码处理onLoad事件
可能注意到,以前称onLoad为属性,而现在将其称为事件。这是因为在XML文件中,能为许多属性定义值,例如onAction、getLabel和onLoad。一旦为某属性赋值,如果能以某种方式触发,将导致事件发生。
因为IRibbonUI对象用于应用程序,所以需要在标准模块的全局声明部分对其声明。
Dim grxIRibbonUI As IRibbonUI
‘Callback for customUI.onLoad
Sub rxIRibbonUI_onLoad(ribbon As IRibbonUI)
    Set grxIRibbonUI = ribbon
End Sub
注意,此时在对代码作出变化后,需要保存、关闭并重新打开工程,才能使改变生效。
三、生成第一个回调
─—如何知道使用哪个回调签名
─—例如,toggleButton有下列签名:
Sub rxtgl_click(control as IRibbonControl,pressed as boolean)
一个普通按钮的签名:
Sub rxbtn_click(control as IRibbonControl)
1、从头开始编写回调
如果知道了回调签名,则不必使用标准的形式声明参数。例如,有一个使用下列XML的toggleButton:
<toggleButton
id=”rxtgl”
label=”Toggle”
size=”large”
onAction=”rxtgl_click”
imageMso=”FormatPainter”/>
编写rxtgl_click回调如下:
Sub rxtgl_click(rxctl As IRibbonControl,toggled As Boolean)
If toggled Then
    MsgBox “I am toggled …And my ID is “ & rxctl.ID,vbInformation
End If
End Sub
注意,无论何时都必须是“正确类型的正确参数”。
也能更改onLoad回调签名来满足需要,如下:
Sub rxIRibbonUI_onLoad(MyRibbon As IRibbonUI)
Set grxIRibbonUI=MyRibbon
End Sub
但是,使用标准的签名及其参数,使他人更容易理解。
表:不同对象属性的回调签名
属性                   回调签名
onLoad                 (ribbon as IRibbonUI)
getLabel,getPressed,
getEnabled,getImage,
getScreentip,getVisible,etc  (control as IRibbonControl,ByRef returnedVal)
onAction(对toggleButton)  (control as IRibbonControl,pressed as Boolean)
onAction(对按钮)         (control as IRibbonControl)
2、使用Office CustomUI Editor生成回调
(1)在CustomUI Editor中打开包含XML代码的Excel或Word文件。(对Access文件,复制并粘贴XML代码到空的CustomUI Editor代码窗口)
(2)单击“Generate Callbacks”按钮。
(3)出现一个新的Callbacks选项卡。
(4)复制并产生的代码粘贴到VBA工程中。
下图为使用CustomUI Editor生成回调的示例:
CusomUIGenerateCallback1
3、理解文件打开时事件的顺序
表:当打开文件后选项卡获取焦点时事件顺序
事件        选项卡获取焦点    选项卡获取焦点    按下ALT键    鼠标在其上方
onLoad      最顶级的事件,当装载UI时发生
getVisible       1                 1                N/A           N/A
getLabel        2                 3                N/A           N/A
getImage        3                 4                N/A          N/A
getEnabled      4                 2                N/A           N/A
getKeytip      N/A               N/A               1             N/A
getScreentip    N/A               N/A              N/A            1
getSupertip    N/A                N/A              N/A            2
4、能够有具有相同名称但不同签名的两个回调吗?
VBA不允许在相同项目中的两个回调使用相同名称但不同的签名。
然而,如果回调在不同的工程中,则相同的回调名称能够有不同的签名。因此,如果同时有一个以上的Word和/或Excel文档打开,可能发现回调返回不可预料的结果。因为如果多个操作与一个回调名称相联系,那么将运行当前文档的回调。
假设打开一个安装了两个加载项的Excel工作簿,三个项目都有一个带有称为rxbtnnsQaShared的控件,当单击UI中该控件时,所期望的是添加一个新工作簿,然而将出现一个消息框。检查后,发现为所有三个按钮都使用了相同的回调。此时,可以使用断点调试,看看单击操作调用了哪个回调。
上述表明,只要在不同工程中,虽然允许使用带有不同签名的一致名称,但这不是一个好主意。
四、调用位于不同工作簿中的过程
与上面所讲的情况相似,如果XML代码运行位于不同工作簿中的VBA,也会碰到类似的问题。
假设有两个工作簿:Book.xlsm和Book2.xlsm,希望在第一个工作簿中添加一个按钮,运行第二个工作簿中的过程,那么使用下面的XML代码创建UI:
<customUI xmlns=”http://schemas.microsoft.com/office/2006/01/customui“>
    <ribbon>
        <tabs>
            <tab id=”rxtabDemo”
                  label=”My Custom Tab”
                  insertBeforeMso=”TabHome”>
                  <group id=”rxgrpDemo”
                         label=”My Demo Group”>
                         <button id=”rxbtnDemo”
                                 label=”My Demo Button”
                                 size=”large”
                                 onAction=”Book2.xlsm!rxbtnDemo_click”
                                 imageMso=”FileStartWorkflow”/>
                  </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>
在Book2.xlsm的标准模块中,放置下列代码:
Sub rxbtnDemo_click(control As IRibbonControl)
    MsgBox “您调用了位于:” & ThisWorkbook.Name & “中的过程.”
End Sub
注意,必须要打开工作簿。
如果希望onAction属性指向加载项,那么简单地在onAction代码名称前使用[add-in name].xlam前缀,例如:
onAction=”myAddIn.xlam!rxbtnDemo_click”
然后,在加载项模块中放置回调VBA代码:
Book3.xlam!rxbtnDemo_click
此时,必须加上前缀xlam!。注意,如果在UI的onAction属性下指定的过程中xlsm和xlam有相同的名称,则该事件会运行包含在活动工作簿中的代码。