在没有模块级变量的情况下使色带控制无效

Invalidate Ribbon Control Without Module-Level Variables

我开发了一个包含自定义功能区的 Excel 加载项。我希望能够在某些情况下使功能区上的控件无效 (enable/disable),但我能找到的每个示例都在首次加载功能区时使用模块级或全局变量来存储功能区对象.这似乎是一个很好的方法,但是,由于 listed here,有些情况下变量可以为空。

所以我想知道,是否有一种不同的方法可以在 Excel 功能区中实现 enabling/disabling 控件的结果,而不使用变量来存储功能区对象,甚至不使用完全使方法无效?

阅读您的描述后,我假设您已经开发了一个纯 Excel VBA Add-In(而不是 Excel VSTO Add-In)。因此,恐怕没有其他方法可以实现您的目标。幸运的是,有一种解决方法可以在重置后恢复对功能区对象的对象引用。

解决方法: 在 "Ribbon_Load" 事件处理程序中,您可以将对象引用设置为 Excel 功能区对象,您还应该保存功能区对象的 "ObjPtr()" 值(例如,在工作表单元格中)。例如像这样:

Public gobjRibbon As Office.IRibbonUI

' Callback for customUI.onLoad
Sub Ribbon_Load(ribbon As Office.IRibbonUI)

    Set gobjRibbon = ribbon

    SampleWorksheet.Cells(1,1).Value = ObjPtr(ribbon)
End Sub

这样做,您可以稍后恢复对功能区对象的引用(如果需要)。您可以通过调用以下示例中的 "RefreshRibbon" 过程(这也会使整个功能区无效)来实现此目的:

#If VBA7 Then
    Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
        ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
#Else
    Declare Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" ( _
        ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
#End If

#If VBA7 Then
Function GetRibbon(ByVal lRibbonPointer As LongPtr) As Object
#Else
Function GetRibbon(ByVal lRibbonPointer As Long) As Object
#End If

    Dim objRibbon As Object

    Call CopyMemory(objRibbon, lRibbonPointer, LenB(lRibbonPointer))

    Set GetRibbon = objRibbon
    Set objRibbon = Nothing
End Function

Public Sub RefreshRibbon()

    If gobjRibbon Is Nothing Then
        Set gobjRibbon = GetRibbon(SampleWorksheet.Cells(1,1).Value)
    ' Else: Do nothing!
    End If

    On Error Resume Next
    gobjRibbon.Invalidate
    On Error GoTo 0
End Sub

我建议在 Excel 会话结束时清除辅助单元格,否则 Excel 有时会意外崩溃。

选择: Re-develop 你的 VBA Add-In 作为 VSTO Add-In 以避免丢失对象引用的麻烦。