VBA-如何临时禁用工作表。激活事件?
我正在使用SAP的BusinessObjects Analysis插件编写Excel工作簿。每当工作簿打开时,都会触发变量选择提示,允许用户输入值,然后用于从后端选择数据,并在Excel中以表格格式显示数据(Excel中SAP BW查询的表示形式)。我面临的问题如下。。。 每当提示选择完成且正在处理选择时,如果垃圾邮件单击工作表选项卡,将触发VBA-如何临时禁用工作表。激活事件?,vba,excel,business-objects,Vba,Excel,Business Objects,我正在使用SAP的BusinessObjects Analysis插件编写Excel工作簿。每当工作簿打开时,都会触发变量选择提示,允许用户输入值,然后用于从后端选择数据,并在Excel中以表格格式显示数据(Excel中SAP BW查询的表示形式)。我面临的问题如下。。。 每当提示选择完成且正在处理选择时,如果垃圾邮件单击工作表选项卡,将触发工作表。激活事件。问题在于工作表.Activate处理程序试图使本身尚未设置的ribbon对象无效。我想防止这种情况发生,我希望功能区仅在设置后才失效。问题
工作表。激活事件。问题在于工作表.Activate
处理程序试图使本身尚未设置的ribbon对象无效。我想防止这种情况发生,我希望功能区仅在设置后才失效。问题是,当工作表发生更改时,功能区必须无效,以便在功能区中加载对于每个工作表都是唯一的特定按钮。激活工作表时不失效不是一个选项。最好在加载自定义功能区之前,消除更改工作表的可能性
以下是我尝试过但没有成功的方法:
我尝试在提示出现时立即使用Application.interactive=False
禁用交互模式,并在执行AOCust\u OnLoad(功能区为IRibbonUI)
ribbonOnLoad
回调并设置功能区时重新启用该模式
我尝试在提示出现时立即使用Application.EnableEvents=False禁用所有事件,并在执行功能区onLoad
回调并设置功能区时重新启用它们
我尝试将以下内容添加到工作表中。激活回调,但它从未退出无限循环,这可能是预期的,因为ribbon onLoad不是系统事件,因此从未触发
while ribbon is Nothing
'waiting for ribbon onload to fire and set the value
DoEvents
wend
第二种情况令人惊讶的是,据我所知,当事件被禁用时,工作表.Activate
事件是如何触发的
您知道我如何解决此问题,以便用户在设置功能区之前无法更改工作表吗
请让我知道您是否希望我在此说明中添加代码段
谢谢
编辑-添加代码
在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
在“自定义功能区”模块中
在模块“AOCust_回调”中
当我在提示选择完成且选择仍在处理时立即单击工作表选项卡时,我不再因为if语句而尝试使功能区无效时未设置变量的问题,但问题是未执行onload ribbon函数。这可能不是b这是一个最简单的解决方案,但却是一种变通方法
您可以使用全局变量来处理它
在模块中放置如下内容
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
变量,您可以让代码忽略激活
过程,即使事件已启用
更新:
你在用Ribbon做什么?这是我过去实现自定义Ribbon的方式,但没有遇到过你的问题:
在我的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>
加载功能区时,它会将其内存值设置为Sheet2
,然后在刷新运行RefreshRibbon的功能区时使用该值重新加载。通过在加载选择提示之前或第一次重新启用问题是SAP决定在BeforeFirstPromptSdisplay上对名为的第一个提示使用不同的回调。因此,我对工作簿中的提示回调所做的更改从未真正触发,因为只有在您自己通过工作簿。在实现了onbeforefirfirstpromptsdisplay
后,一切正常。
感谢您的输入!这是一个很好的解决方案,我最初考虑过这一点!我希望通过设置VBA事件属性来实现更健壮的实现,但这会起到作用。如果没有其他更健壮的解决方案,我会将其标记为正确答案。谢谢我以我设置EventsEnabled的方式实现了这一点当提示出现时将其设置为False,并在ribbon onLoad中设置ribbon后将其更改为True。现在的问题是,当我垃圾邮件单击时,ribbon onLoad根本不会执行。您可以发布任何代码吗?自定义ribbon的一个主要问题是它的文档记录非常糟糕。请查看我编辑的帖子-我添加了一些代码。我希望它有帮助。谢谢你这么快的响应。顺便说一句。你能看看我的更新吗。我认为从你的代码来看,问题是当你使它无效时,你正在丢失它的内存分配。调试功能区很难,因为调试器不能真正使用它,尽管我在你的代码中看不到你在哪里设置Application.EnableEvents=False
。拥有一个全局变量EnableEvents
不是一回事。是的,我知道。在发布代码片段之前,我已经去掉了这些代码。
Private Sub Worksheet_Activate()
If Not EventsEnabled Then
' Do activate code here
End If
End Sub
<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>
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