TL;DR —
Application.EnableEvents = Falseimpide que las escrituras de tu macro disparen los manejadores de eventos —Worksheet_Change,Workbook_Openy los demás. Su tarea principal es romper el bucle en el que un manejadorWorksheet_Changeescribe en una celda, lo que disparaWorksheet_Changeotra vez, sin fin. Es un interruptor de corrección, no de velocidad. Y es el que más necesita un manejador de errores, porqueEnableEventses a nivel de aplicación y no se reinicia solo — falla con él apagado y cada evento de Excel se queda muerto hasta que reinicies:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("B:B")) Is Nothing Then Exit Sub
Application.EnableEvents = False ' nuestra escritura de abajo NO debe volver a disparar este manejador
On Error GoTo CleanExit
Target.Offset(0, 1).Value = Now ' escritura - si no, volveria a disparar Worksheet_Change
CleanExit:
Application.EnableEvents = True ' restaura, incluso tras un error, o los eventos quedan muertos en toda la app
End Sub
Los otros dos interruptores de este clúster van de velocidad —
ScreenUpdating detiene los repintados,
Calculation detiene los recálculos. EnableEvents es distinto. Va de
corrección: evitar que tus propias escrituras reboten por los manejadores de eventos que vigilan el
libro. Esta guía se construye sobre una sola idea — EnableEvents es el interruptor que accionas para
que tus cambios no disparen el código que reacciona a los cambios. Lo accionas por control, no por
velocidad — y como un fallo lo deja apagado para toda la aplicación, restaurarlo no es opcional.
Lo que aprenderás
- El modelo mental — escribir en una celda puede disparar manejadores de eventos, que pueden escribir en más celdas
- El bug clásico — un manejador
Worksheet_Changeque se dispara a sí mismo hasta un bucle infinito - La regla más importante —
EnableEventses a nivel de aplicación y no se reinicia solo - Por qué «mis botones dejaron de funcionar» es casi siempre un
EnableEvents = Falseque se quedó colgado - El restaurado con
CleanExit, y por qué aquí importa más que con los interruptores de velocidad - Cómo se empareja con Worksheet_Change e Intersect
El modelo mental: las escrituras pueden disparar eventos
Los libros de Excel pueden llevar manejadores de eventos — procedimientos que se ejecutan
automáticamente cuando pasa algo. Worksheet_Change se ejecuta cuando cambia una celda; Workbook_Open
se ejecuta cuando se abre el archivo; Worksheet_SelectionChange se ejecuta cuando se mueve la
selección. Así es como un libro reacciona al usuario.
La trampa: las acciones de tu macro también cuentan como «algo que pasa». Cuando tu código escribe
en una celda, eso es un cambio, así que Excel dispara Worksheet_Change — aunque fuera tu macro, y no
el usuario, quien hizo la edición. Normalmente no quieres que tus propias escrituras automatizadas
despierten a los manejadores que se escribieron para responder a una persona.
Application.EnableEvents = False apaga ese disparo. Mientras está en False, los cambios siguen
ocurriendo, pero Excel no ejecuta ningún manejador de eventos en respuesta. Vuelve a ponerlo en True
y los eventos se reanudan.
El bug clásico: un manejador que se dispara a sí mismo
El fallo que este interruptor existe para prevenir es el Worksheet_Change que se dispara a sí mismo.
Imagina un manejador que sella la hora cada vez que se edita la columna B — escribiendo en la columna C:
' ROTO - recursion infinita:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("B:B")) Is Nothing Then Exit Sub
Target.Offset(0, 1).Value = Now ' escribir en C es en si mismo un cambio...
End Sub ' ...que dispara Worksheet_Change otra vez -> otra vez -> cuelgue
Escribir en C es un cambio, que dispara Worksheet_Change, que escribe en C otra vez, que lo
dispara de nuevo. En la práctica te llevas un desbordamiento de pila (error 28) o Excel atascado en
un bucle. El arreglo es envolver la escritura para que no vuelva a entrar en el manejador:
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Me.Range("B:B")) Is Nothing Then Exit Sub
Application.EnableEvents = False ' la escritura de abajo no volvera a disparar esto
On Error GoTo CleanExit
Target.Offset(0, 1).Value = Now
CleanExit:
Application.EnableEvents = True
End Sub
La guarda Intersect y la guarda EnableEvents son hermanas — un manejador
Worksheet_Change que escriba cualquier cosa de vuelta en la hoja
necesita las dos, una para acotar el disparo y otra para detener la recursión.
La regla más importante: no se reinicia solo
Aquí es donde EnableEvents se gana su fama de interruptor que hay que manejar con cuidado. A
diferencia de ScreenUpdating, que Excel a veces restaura cuando una
macro termina, EnableEvents nunca se reinicia por su cuenta. Y es una propiedad de
Application, no una por libro — así que se aplica a todos los libros abiertos a la vez.
Junta esos dos hechos y tienes el estado residual más desagradable de VBA. Si una macro pone
EnableEvents = False y luego falla antes de restaurarlo, los eventos están ahora apagados en todas
partes — en ese libro y en todos los demás que estén abiertos — y siguen apagados hasta que el
usuario cierra y vuelve a abrir Excel. Ningún mensaje de error, ninguna señal visible. El libro
sencillamente deja de reaccionar en silencio.
«Mis botones dejaron de funcionar»
Ese estado residual tiene una queja característica: «mis botones de macro / mis listas desplegables /
mi formato automático dejaron de funcionar, y no cambié nada.» Nueve de cada diez veces, alguna macro
anterior se colgó con EnableEvents = False todavía en efecto, y ahora Worksheet_Change,
Workbook_Open y todos los demás manejadores están desactivados en silencio.
El rescate de una línea es ejecutar esto desde la ventana Inmediato (o cualquier macro):
Application.EnableEvents = True
Pero el arreglo de verdad está aguas arriba: nunca pongas EnableEvents = False sin un manejador
de errores que lo restaure. Como el daño es a nivel de toda la aplicación e invisible, la disciplina
CleanExit que es simplemente una buena práctica para los interruptores de velocidad, aquí es
genuinamente obligatoria.
Sub BulkImport()
Application.EnableEvents = False
On Error GoTo CleanExit
' ... escrituras que si no dispararian Worksheet_Change en cada fila ...
CleanExit:
Application.EnableEvents = True ' no negociable
End Sub
Cuándo usarlo — y cuándo no
Echa mano de EnableEvents = False cuando tu código escribe en celdas que tienen manejadores de
eventos vigilándolas, o durante una operación masiva en la que no quieres que los eventos por fila se
disparen cientos de veces. No eches mano de él como truco de velocidad general — si la hoja no
tiene manejadores de eventos relevantes, desactivar los eventos no cambia nada, y has asumido el riesgo
de la restauración sin ningún beneficio. Es una herramienta de corrección específica: úsalo justo donde
tus escrituras rebotarían de otro modo, y déjalo en paz en el resto de los casos.
Cómo ayuda ExcelMaster
EnableEvents es engañosamente arriesgado: es a nivel de toda la aplicación, nunca se reinicia, y un
fallo con él apagado mata en silencio cada evento de Excel hasta un reinicio. Usarlo con seguridad
significa emparejarlo con una guarda Intersect dentro de los manejadores de eventos, envolver las
escrituras masivas para que no disparen eventos por fila, y restaurarlo en un manejador CleanExit
todas y cada una de las veces.
ExcelMaster construye el
patrón seguro completo por ti. Pide «sella la hora en la columna C cuando cambie la columna B» y escribe
el manejador Worksheet_Change con la guarda Intersect, el interruptor EnableEvents = False
alrededor de la escritura, y el restaurado CleanExit — para que el manejador nunca entre en bucle
consigo mismo y nunca deje los eventos colgados el resto de la sesión. Te llevas una automatización de
libro que reacciona correctamente, no una que se rompe en silencio tras el primer error.
Preguntas frecuentes
¿Qué hace Application.EnableEvents = False en VBA?
Impide que Excel ejecute los manejadores de eventos en respuesta a los cambios que hace tu código.
Mientras está en False, acciones como escribir en una celda siguen ocurriendo, pero no disparan
Worksheet_Change, Workbook_SheetChange ni otros procedimientos de evento. Vuelve a ponerlo en
True para que los eventos se disparen de nuevo.
¿Cómo evito que un evento Worksheet_Change se dispare a sí mismo?
Pon Application.EnableEvents = False antes de que tu manejador escriba en ninguna celda, y luego
restáuralo a True después. Sin eso, la propia escritura del manejador es un cambio que dispara
Worksheet_Change otra vez, entrando en bucle hasta que Excel lanza un error de desbordamiento de
pila. Combínalo con una guarda Intersect para que el manejador solo se ejecute con las celdas que te
importan.
¿Por qué dejaron de funcionar todos mis eventos de Excel?
Porque alguna macro puso Application.EnableEvents = False y nunca lo restauró — normalmente falló
antes de la línea de restauración. EnableEvents es a nivel de aplicación y no se reinicia por su
cuenta, así que los eventos siguen desactivados para todos los libros abiertos hasta que pongas
Application.EnableEvents = True o reinicies Excel.
¿EnableEvents se reinicia automáticamente cuando la macro termina?
No. A diferencia de ScreenUpdating, que Excel puede restaurar por su cuenta, EnableEvents se queda
exactamente donde lo dejaste — de una macro a otra e incluso después de que la macro termine — hasta
que lo vuelvas a poner o cierres Excel. Por eso debes restaurarlo en un manejador de errores en lugar
de fiarte de ningún reinicio automático.
¿EnableEvents es una optimización de velocidad como ScreenUpdating?
En realidad no. ScreenUpdating y Calculation van de velocidad; EnableEvents va de corrección —
evitar que tus escrituras disparen los manejadores que vigilan el libro. Puede ahorrarte ejecutar
código de evento cientos de veces durante una escritura masiva, pero su propósito principal es prevenir
bucles y reacciones no deseadas, no la velocidad pura.
Probado en
Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 17/08/2026.
Guías relacionadas: VBA ScreenUpdating · VBA Calculation · VBA Worksheet_Change · VBA Intersect · VBA On Error
