VBA - 如何暂时禁用Worksheet.Activate事件?

时间:2018-04-18 09:07:58

标签: excel vba excel-vba business-objects

我正在使用SAP的BusinessObjects Analysis插件的Excel工作簿。每当工作簿打开时,都会触发变量选择提示,并允许用户输入值,然后使用这些值从后端选择数据并在Excel中以表格格式显示(Excel中的SAP BW查询的表示)。我面临的问题是以下问题...... 每当提示选择完成并且正在处理选择时,如果您是垃圾邮件,请单击工作表选项卡以触发Worksheet.Activate事件。问题是Worksheet.Activate处理程序尝试使尚未设置的功能区对象无效。我想阻止它,我希望功能区只有在设置后才会失效。问题是,更改工作表时,功能区必须无效,以便加载功能区中的特定按钮,这些按钮对于每个工作表都是唯一的。激活工作表时无效无效。在加载自定义功能区之前,最好省去更改工作表的可能性。

这是我尝试过但没有取得任何成功:

  1. 我尝试在出现提示后立即使用Application.Interactive = False禁用交互模式,并在执行AOCust_OnLoad(ribbon As IRibbonUI)功能区onLoad回调并设置功能区时重新启用它

  2. 我尝试在出现提示后立即使用Application.EnableEvents = False停用所有事件,并在执行功能区onLoad回调并设置功能区时重新启用它们。

  3. 我尝试将以下内容添加到Worksheet.Activate回调中,但它永远不会退出可能需要的无限循环,因为功能区onLoad不是系统事件,因此永远不会被触发。

    while ribbon is Nothing
      'waiting for ribbon onload to fire and set the value
      DoEvents
    wend
    
  4. 第二种情况令人惊讶的是,根据我的理解,当事件被禁用时,如何触发Worksheet.Activate事件。

    您是否知道如何解决此问题,以便用户在设置功能区之前无法更改工作表?

    如果您希望我在此说明中添加代码段,请与我们联系。

    由于

    编辑 - 添加代码

    在ThisWorkbook中的Microsoft Excel对象

    Private Sub Workbook_SheetActivate(ByVal Sh As Object)
      If EnableEvents = True Then
          Debug.Print "invalidate"
          Call AOCust_Callbacks.AOCust_InvalidateRibbon
      End If
    End Sub
    

    在模块“Custom_Ribbon”

    'Callback for Selections data onAction
     Sub PROMPT(control As IRibbonControl)
       EnableEvents = False
       'more prompt-related code
     End Sub
    

    在模块'AOCust_Callbacks'中

    Public EnableEvents As Boolean
    
    'Callback for Ribbon OnLoad
    Sub AOCust_OnLoad(ribbon As IRibbonUI)
      Debug.Print "setting the ribbon"
      'Start Highlighting for Workbook
      StartHighlighting
      Set AOCustRibbon = ribbon
      Debug.Print "the ribbon is now set"
      EnableEvents = True
    End Sub
    

    当我垃圾邮件时,一旦提示选择完成并且选择仍在处理时单击工作表选项卡,当我因为if语句尝试使功能区无效时,我不再遇到未设置变量的问题,但问题是没有执行onload功能。

2 个答案:

答案 0 :(得分:0)

这可能不是最佳解决方案,但可以解决这个问题。

您可以使用全局变量来处理它。

在模块中放置如下内容

Public EventsEnabled As Boolean
Public Sub ModuleWithDisabledEvents()
    EventsEnabled = False
    Debug.Print EventsEnabled
    EventsEnabled = True
    Debug.Print EventsEnabled
End Sub

然后在您的工作表上激活将Activate代码包装在查看此变量的if块中

Private Sub Worksheet_Activate()
    If Not EventsEnabled Then
        ' Do activate code here
    End If
End Sub

通过更改EventsEnabled变量,即使启用了事件,您也可以让代码忽略Activate程序。

<强>更新: 你在用丝带做什么?这就是我过去实施自定义色带的方式,并且没有经历过您的问题:

在我的XML文件中,我有以下内容:

<customUI onLoad="RibbonOnLoad" xmlns="http://schemas.microsoft.com/office/2009/07/customui">
    <ribbon startFromScratch="false">
        <tabs>
            <tab id="customTab" label="Custom Tab">
                <group id="customGroup" label="Custom Group">
                    <button id="customButton" label="Custom Button" imageMso="HappyFace" size="large" onAction="Callback" getVisible="GetVisible" />
                </group>
            </tab>
        </tabs>
    </ribbon>
</customUI>

然后在我的文件中,我有一个名为&#39; Ribbon&#39;其中包含:

Option Explicit
Option Private Module
Dim rib As IRibbonUI

Private Declare Function ShellExecute _
                         Lib "shell32.dll" Alias "ShellExecuteA" ( _
                         ByVal hWnd As Long, _
                         ByVal Operation As String, _
                         ByVal Filename As String, _
                         Optional ByVal Parameters As String, _
                         Optional ByVal Directory As String, _
                         Optional ByVal WindowStyle As Long = vbMinimizedFocus _
                         ) As Long

#If VBA7 Then
    Public Declare PtrSafe Sub CopyMemory Lib "kernel32" Alias "RtlMoveMemory" (ByRef Destination As Any, ByRef Source As Any, ByVal Length As Long)
#Else
    Public 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
CopyMemory objRibbon, lRibbonPointer, LenB(lRibbonPointer)
Set GetRibbon = objRibbon
Set objRibbon = Nothing
End Function
Public Sub RibbonOnLoad(ribbon As IRibbonUI)
    Set rib = ribbon
    Debug.Print "ribbon:-", ObjPtr(ribbon)
    Sheet2.Cells(1, 1).Value = ObjPtr(ribbon)
End Sub
Public Sub RefreshRibbon()
    On Error GoTo RibbonError
    If rib Is Nothing Then
        Set rib = GetRibbon(Sheet2.Cells(1, 1).Value)
        If rib Is Nothing Then GoTo RibbonError
    Else
        rib.Invalidate
        Exit Sub
    End If
    Exit Sub
RibbonError:
    Debug.Print "There is an issue with the menu bar. Please restart the tool"
End Sub

Public Sub GetVisible(control As IRibbonControl, ByRef visible)
    visible = True
End Sub

当功能区加载时,它会将其内存值设置为Sheet2,然后当它刷新正在运行的功能区RefreshRibbon

时,它会用来重新加载

答案 1 :(得分:0)

通过在选择提示加载之前使用Application.interactive = False禁用鼠标事件或第一次禁用鼠标事件并在功能区加载时重新启用它们来解决问题。问题是SAP决定对第一个名为onBeforeFirstPromptsDisplay的提示使用不同的回调。结果,我对工作簿中的提示回调的更改从未实际触发,因为只有在触发时才会执行回调通过工作簿提示自己。实施onBeforeFirstPromptsDisplay之后一切正常。 感谢您的投入!