在没有模块级变量的情况下使功能区控件无效

时间:2015-12-16 18:27:54

标签: excel-vba ms-office ribbon excel-2013 vba

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

所以我想知道,是否有不同的方法来实现在Excel功能区中启用/禁用控件的结果,而不使用变量来存储功能区对象或甚至根本不使用invalidate方法?

1 个答案:

答案 0 :(得分:3)

阅读完您的描述后,我假设您开发了一个纯Excel VBA加载项(而不是Excel VSTO加载项)。因此,我担心没有其他办法可以实现你的目标。幸运的是,有一种解决方法可以在重置后恢复对象对象的对象引用。

解决方法: 在“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有时会崩溃。

<强>替代: 将VBA加载项重新开发为VSTO加载项,以避免丢失对象引用时出现问题。