绕过Workbook_SheetChange事件

时间:2017-06-21 08:27:21

标签: vba excel-vba excel

我不知道为什么,这很奇怪,但我的代码是循环的。实际上,在第一张(ws1)中,我在Worksheet_Change事件中执行此操作:

Application.EnableEvents = False
ws2.Range(Col_Letter(target.Column) & LastLine & ":" & Col_Letter(target.Column) & LastLine ).PasteSpecial Paste:=xlPasteValues
Application.EnableEvents = True

此外,我在ThisWorkbook"班级",Workbook_SheetChange事件。

在上面的代码中,我修改了一个Cell。 问题我不知道它为什么要调用Workbook_SheetChange事件,因为我已经在我的第一张工作表上禁用了这些事件。

因此,它会循环播放,因为在我的Workbook_SheetChange事件中我修改了工作表1。然后,Worksheet1正在修改第二个,....无限循环。

我不知道为什么Application.EnableEvents = False不起作用(事实上,如果我在Workbook_SheetChange上执行Debug.Print(Application.EnableEvents)事件,它说"真的"这是非常不安。)

谢谢, 克莱门特

1 个答案:

答案 0 :(得分:1)

如果您使用全局标记来指示正在进行何种处理,则可以解决此问题而无需禁用事件。

您的设计说明中并不完全清楚为什么您需要同时处理Worksheet_Change个事件和Workbook_SheetChange个事件。但是对每个事件何时开火的充分理解肯定有帮助。在您的情况下,如果您更改Sheet1上的单元格,您将获得Sheet1的Worksheet_Change事件,然后获得Workbook_SheetChange事件。只要您更改任何工作表,就会发生这种情况。

下面的示例说明了如何处理处理以保持一切正常,而不是踩到您通过VBA进行的更改以及手动进行的更改。这个例子有多个部分,所以请在家里跟着......

首先,我们需要建立两个Public事物:一个工作簿 - 全局标志和一个工作簿 - 全局子例程来执行您的处理。所以在VBA代码模块(Module1)中,我们有以下代码:

'------ Module1 --------
Option Explicit

Public MyCustomMacroInProgress As Boolean

Public Sub DistributeChangeToSheets()
    Debug.Print "Entering DistributeChangeToSheets... "
    MyCustomMacroInProgress = True
    Debug.Print "=== setting MyCustomMacroInProgress = " & MyCustomMacroInProgress

    '--- loop to fire change events in the other worksheets for testing
    Dim ws As Variant
    For Each ws In ThisWorkbook.Sheets
        If ws.Name <> "Sheet1" Then
            ws.Range("A1") = 1
        End If
    Next ws

    MyCustomMacroInProgress = False
    Debug.Print "=== setting MyCustomMacroInProgress = " & MyCustomMacroInProgress
    Debug.Print "Leaving DistributeChangeToSheets"
End Sub

(请注意,在任何地方使用Option Explicit可以极大地帮助您的代码。)

通过创建公共全局标志(MyCustomMacroInProgress),您现在可以在任何模块以及任何类和任何工作表中检查此标志。通过在模块中创建Sub DistributeChangeToSheets并将其公开,您基本上可以从您可能想要的任何原始工作表中应用此类处理。我的示例仅应用Sheet1的更改。

所以现在主要改变捕手 - Sheet1。在Sheet1的代码中,我有

Option Explicit

'--- in Sheet1
Private Sub Worksheet_Change(ByVal Target As Range)
    Debug.Print "In " & Target.Parent.Name;
    Debug.Print ": Worksheet_Change event fired ";
    Debug.Print " - changed cell " & Target.Address

    DistributeChangeToSheets
End Sub

我在任何地方都打印Debug语句,因此在处理过程中更容易理解。您可以在Sheet1中看到,我们正在打印我们所在的位置,然后将子调用DistributeChangesToSheets(来自Module1)。

我的示例只有三个工作表,因此其他工作表模块中的代码很简单:

Option Explicit

'--- in Sheet2
Private Sub Worksheet_Change(ByVal Target As Range)
    Debug.Print "In " & Target.Parent.Name;
    Debug.Print ": Worksheet_Change event fired ";

    If Not MyCustomMacroInProgress Then
        Debug.Print " - process change event normally"
    Else
        Debug.Print " - skip normal change event processing"
    End If
End Sub

Option Explicit

'--- in Sheet3
Private Sub Worksheet_Change(ByVal Target As Range)
    Debug.Print "In " & Target.Parent.Name;
    Debug.Print ": Worksheet_Change event fired ";

    If Not MyCustomMacroInProgress Then
        Debug.Print " - process change event normally"
    Else
        Debug.Print " - skip normal change event processing"
    End If
End Sub

现在在示例中将所有内容放在一起,在Sheet1上的任何单元格中键入一个值。立即窗口现在显示以下输出:

In Sheet1: Worksheet_Change event fired  - changed cell $B$2
Entering DistributeChangeToSheets... 
=== setting MyCustomMacroInProgress = True
In Sheet2: Worksheet_Change event fired  - skip normal change event processing
In Sheet2: Workbook_SheetChange event fired  - skip normal change event processing
In Sheet3: Worksheet_Change event fired  - skip normal change event processing
In Sheet3: Workbook_SheetChange event fired  - skip normal change event processing
=== setting MyCustomMacroInProgress = False
Leaving DistributeChangeToSheets
In Sheet1: Workbook_SheetChange event fired  - process change event normally

从输出中,您可以看到工作表和工作簿事件都遵循事件模式 - 因此在更改工作表(Worksheet_ChangeWorkbook_SheetChange)时会收到两个事件。通过在Sheet1上设置全局标志(从DistributeChangeToSheets内部),通过使用If语句,您可以在此类处理期间禁止对所有其他工作表进行更改处理。

可能需要对您进行一些重新编码,但是以有序的方式处理您的事件可以使处理流程更加清晰。