Application.EnableEvents
不是变量,而是属性。您不能像 VB(A) 中那样通过引用传递属性,编译器将创建当前属性值的临时副本,并且您的哨兵将在该副本上“关闭”。
要以这种方式管理对象属性,您可以这样做:
创建一个类,将其命名为例如SentryForPropertiesVariant
并使用类似的代码:
Option Explicit
Private m_Obj As Object
Private m_PropertyName As String
Private m_OldValue As Variant
Public Sub Init(ByVal obj As Object, ByVal PropertyName As String, ByVal NewValue As Variant)
Set m_Obj = obj
m_PropertyName = PropertyName
m_OldValue = CallByName(obj, m_PropertyName, VbGet)
CallByName m_Obj, m_PropertyName, VbLet, NewValue
End Sub
Private Sub Class_Terminate()
If Not m_Obj Is Nothing Then
CallByName m_Obj, m_PropertyName, VbLet, m_OldValue
End If
End Sub
然后使用它:
Dim s As SentryForPropertiesVariant
Set s = New SentryForPropertiesVariant
s.Init Application, "EnableEvents", False
您还可以在模块中拥有辅助函数:
Public Function CreateSentry(ByVal obj As Object, ByVal PropertyName As String, ByVal NewValue As Variant) As SentryForPropertiesVariant
Set CreateSentry = New SentryForPropertiesVariant
CreateSentry.Init obj, PropertyName, NewValue
End Function
此时使用变得更简单:
Dim s As SentryForPropertiesVariant
Set s = CreateSentry(Application, "EnableEvents", False)
在这种情况下你可能想要更换Public Sub Init
with Friend Sub Init
.
如果您计划将哨兵类存储在共享加载项 (.xla) 中,则无论如何都必须具有此类辅助函数,因为加载项中定义的类无法从其他工作簿中的代码创建,因此解决方案是还在同一工作簿中定义一个函数作为创建实例并将其返回给外部调用者的类。
最后,可以方便地控制此类哨兵的生命周期With
(类似于 C# 的using
):
With CreateSentry(Application, "EnableEvents", False)
'Here EnableEvents is False
End With
'Here it's True
然而,在这样做时,您应该记住With
only 类似于 using
。如果你过早地跳出它GoTo
, the End With
陈述不会被执行,这意味着保存哨兵实例的临时变量将一直存在到过程结束,并且在此之前该属性不会恢复为其原始值。
所以不要跳出这些障碍。如果确实有必要,请在之前创建一个标签End With
然后跳到那个。