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

ARi*_*ich 4 excel vba ribbon ms-office excel-2013

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

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

小智 5

阅读您的描述后,我假设您已经开发了一个纯 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
Run Code Online (Sandbox Code Playgroud)

这样做之后,您可以稍后恢复对功能区对象的引用(如有必要)。您可以通过调用以下示例中的“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
Run Code Online (Sandbox Code Playgroud)

我建议在 Excel 会话结束时清除辅助单元格,否则 Excel 有时会令人惊讶地崩溃。

替代方法: 将您的 VBA 加载项重新开发为 VSTO 加载项,以避免出现丢失对象引用的问题。

  • 谢谢,帕特里克。我没有将指针值存储在单元格中,而是使用了 ***隐藏名称***,在工作簿关闭时将其删除。我认为这将最大限度地减少它被意外更改的可能性。此外,在调用 `Invalidate` 之前,我会检查 `gobjRibbon` 是否不是 `Nothing`。我这样做是因为我根据哪个工作表处于活动状态更改了功能区上某些按钮的“已启用”属性;并且`WorksheetActivate`在功能区加载之前***调用,并且对象指针已经设置。这使我的崩溃为零。再次感谢。 (2认同)