“Event procedures” like Worksheet_Change are very convenient features that allow macros to execute automatically based on specific actions. However, if used incorrectly, they can cause unintended infinite loops (chain reactions), causing Excel to freeze.
To prevent this, the most important and essential technique is to temporarily turn off events using the Application.EnableEvents property.
This article explains the standard code pattern, including error handling, to safely control events.
Why Do You Need to Stop Events?
A typical example is the Worksheet_Change event. This runs when “a cell value on the sheet is changed.”
' Bad example causing an infinite loop
Private Sub Worksheet_Change(ByVal Target As Range)
' If the value in column B changes, timestamp column C
If Target.Column = 2 Then
' Change the value in column C here
Cells(Target.Row, 3).Value = Now()
' This change calls the Worksheet_Change event again, causing an infinite loop!
End If
End Sub
In the code above, the macro itself rewrites a cell, which calls the same macro again, resulting in an infinite loop.
To prevent this, you must temporarily stop the generation of events before the macro rewrites the cell, and turn them back on after the rewriting is finished.
Completed VBA Code (Recommended Pattern with Error Handling)
When handling Application.EnableEvents, it is a golden rule to include error handling to ensure that events are always returned to an enabled state, even if an error occurs midway.
Private Sub Worksheet_Change(ByVal Target As Range)
' Specify the cell range targeted by this event procedure
Dim checkRange As Range
Set checkRange = Me.Range("B2:B100")
' If the changed cell (Target) is not in the target range, do nothing
If Intersect(Target, checkRange) Is Nothing Then Exit Sub
'--- 1. Temporarily stop event generation ---
Application.EnableEvents = False
' Preparation to ensure events are re-enabled even if an error occurs
On Error GoTo ErrorHandler
'--- 2. Main Process ---
' Enter the update date/time next to the changed cell (Column C)
Me.Cells(Target.Row, "C").Value = Now()
'--- 3. Re-enable events [Important] Always executed ---
ExitRoutine:
Application.EnableEvents = True
Exit Sub
ErrorHandler:
' Jump here if an error occurs and display a message
MsgBox "An error occurred: " & Err.Description, vbCritical
' Proceed to ExitRoutine to re-enable events
Resume ExitRoutine
End Sub
Explanation of Code Points
1. Disabling Events: Application.EnableEvents = False
Application.EnableEvents = False is the master switch that suppresses event generation for the entire Excel application. When this is set to False, even if VBA changes a cell value, the next Worksheet_Change event will not be called.
Write this immediately before the process that might trigger an event (in this example, Me.Cells(...).Value = Now()).
2. Re-enabling Events: Application.EnableEvents = True
Once the process is finished, you must restore event generation with Application.EnableEvents = True.
If you forget this, all events (including manual cell changes or button clicks) will stop working even after the macro finishes, and normal operations will not be possible until Excel is restarted.
3. Why is Error Handling Important?
If an error occurs in the main processing part and the macro is interrupted, the line Application.EnableEvents = True will not be executed, and events will remain disabled.
By using the error handling syntax combining On Error GoTo ErrorHandler and Resume ExitRoutine, you guarantee that the processing under the ExitRoutine: label (processing to return events to True) is executed whether the process completes normally or an error occurs midway. This is the “standard practice” for safely using EnableEvents.
Summary
When writing code that changes cell values within an event procedure, which could cause an event chain, always adhere to the following pattern:
- Write
Application.EnableEvents = Falseimmediately after starting the specific process. - Use
On Error GoToto ensure that specific cleanup code is always executed at the end. - Write the main processing.
- At the exit of the code, always execute
Application.EnableEvents = Trueto return events to an enabled state, regardless of whether the process ended normally or with an error.
This pattern is one of the most important techniques for creating stable and predictable event-driven macros.
