TL;DR —
Worksheet_Changees un evento que Excel dispara cada vez que un usuario (o tu código) edita una celda de esa hoja. Excel te entrega la celda modificada comoTarget, así que puedes reaccionar: sellar la fila con la hora, validar la entrada, registrar la edición. Lo único que debes saber: si tu manejador escribe en una celda, esa escritura vuelve a dispararWorksheet_Change— y otra vez — hasta que Excel se congela. El arreglo es un solo par de líneas,Application.EnableEvents = False … = True, alrededor de cada escritura. Interioriza ese reflejo y todo lo demás es detalle.
' Vive en el propio objeto de la hoja (p. ej. Sheet1), NO en un Module ni en ThisWorkbook.
Private Sub Worksheet_Change(ByVal Target As Range)
If Intersect(Target, Range("B:B")) Is Nothing Then Exit Sub ' solo reacciona a la columna B
On Error GoTo Done
Application.EnableEvents = False ' evita que nuestra propia escritura vuelva a disparar el evento
Target.Offset(0, 1).Value = Now ' sella la hora junto a la edición
Done:
Application.EnableEvents = True ' SIEMPRE vuelve a activar los eventos
End Sub
Reaccionar a las ediciones es donde VBA deja de ser «botones que ejecutan macros» y
empieza a sentirse vivo: una celda cambia y la hoja responde por su cuenta.
Worksheet_Change es el evento que da vida a los registros de auditoría, las marcas de
tiempo automáticas, la validación en directo y las listas desplegables dependientes. Es
también el evento que produce los momentos más angustiosos de «Excel se congeló y perdí
mi trabajo» — porque el código obvio está a un pequeño paso de un bucle infinito.
Lo que aprenderás
- El modelo mental — un sensor de ediciones que te entrega la celda modificada como
Target - La trampa del bucle infinito — y el arreglo con
Application.EnableEventsque define al VBA de eventos - Por qué un fallo puede apagar todos tus eventos hasta que reinicies Excel
- Cómo acotar el manejador con
Intersectpara que no se ejecute en cada edición - Por qué ignora los recálculos de fórmulas — y cuándo necesitas
Worksheet_Calculateen su lugar
El modelo mental: un sensor de ediciones, no un botón
Worksheet_Change es un sensor cableado a la hoja. Tú no lo llamas; en el momento en
que cambia el contenido de una celda, Excel te llama a ti, pasándote la celda (o
celdas) modificada como un Range llamado Target. Tu trabajo es leer Target y
decidir qué hacer con él.
Ese enfoque resuelve dos cosas. Primero, Target es toda tu entrada — es donde ocurrió
la edición, y puede ser una celda o muchas (un pegado, un relleno o un borrado a lo
largo de una selección llegan todos como un Target de varias celdas). Segundo, el
manejador vive en el objeto de código de la hoja concreta —Sheet1 en el Explorador
de proyectos, no ThisWorkbook ni un Module. La firma es fija:
Private Sub Worksheet_Change(ByVal Target As Range). (La versión para todo el libro,
para todas las hojas a la vez, es Workbook_SheetChange en ThisWorkbook.)
La trampa que congela Excel: tu escritura vuelve a disparar el evento
Aquí está el bug que todo desarrollador de VBA escribe exactamente una vez. Quieres reaccionar a una edición escribiendo algo de vuelta en la hoja:
Private Sub Worksheet_Change(ByVal Target As Range)
Target.Offset(0, 1).Value = Now ' escribe junto a la edición... lo cual es EN SÍ MISMO una edición
End Sub
Escribir en Target.Offset(0, 1) cambia una celda — lo que dispara Worksheet_Change
otra vez — cuya escritura lo dispara de nuevo — para siempre. Excel entra en recursión
hasta que se queda sin pila y lanza un error, o simplemente parece congelado. El evento
de cambio no tiene ninguna protección incorporada contra reaccionar a su propia
reacción.
El arreglo es el patrón más importante del VBA de eventos: apaga los eventos alrededor de cualquier escritura y luego vuelve a encenderlos.
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents = False
Target.Offset(0, 1).Value = Now
Application.EnableEvents = True
End Sub
Con EnableEvents = False, tu escritura no dispara un nuevo Worksheet_Change, así que
no hay recursión. Después lo restauras. Grábate la regla a fuego: dentro de cualquier
evento que escriba en celdas, envuelve la escritura en
Application.EnableEvents = False … = True.
La regla que esconde la segunda mitad de la trampa: un fallo deja los eventos apagados
Application.EnableEvents es un único interruptor global de la aplicación, y Excel
no lo restaura automáticamente. Eso crea un segundo modo de fallo desagradable: si tu
manejador falla después de ponerlo en False pero antes de devolverlo a su sitio,
los eventos se quedan apagados — durante toda la sesión de Excel, en cada hoja y cada
libro.
El síntoma es desconcertante: «mis macros dejaron de funcionar sin más». Tu
Worksheet_Change no se rompió — los eventos están suprimidos globalmente porque una
ejecución anterior murió a mitad del manejador. Por eso el patrón seguro siempre vuelve
a activar los eventos en un manejador de errores:
Private Sub Worksheet_Change(ByVal Target As Range)
On Error GoTo CleanExit
Application.EnableEvents = False
Target.Offset(0, 1).Value = Now
' ... más lógica que podría fallar ...
CleanExit:
Application.EnableEvents = True ' se ejecuta tanto si tuvimos éxito como si falló
End Sub
Es exactamente la disciplina de «una única salida que siempre limpia» de
VBA On Error, y aquí no es negociable. (Si los eventos ya están
atascados en apagado, ejecuta una línea en la ventana Inmediato —
Application.EnableEvents = True — o simplemente reinicia Excel.)
La regla que lo mantiene enfocado: acótalo con Intersect
Un Worksheet_Change a secas se dispara con cualquier celda de la hoja. Si solo te
importan las ediciones en una columna o una tabla, tienes que decirlo — de lo contrario
el manejador se ejecuta (y quizá escribe) en cada edición que no viene a cuento. La
herramienta es Intersect, que devuelve el solapamiento entre Target y el rango que
te importa, o Nothing si no hay ninguno:
Private Sub Worksheet_Change(ByVal Target As Range)
' Ignora las ediciones fuera de B2:B1000
If Intersect(Target, Range("B2:B1000")) Is Nothing Then Exit Sub
' ... reacciona solo a la parte que importa ...
End Sub
Dos advertencias relacionadas. Target puede ser muchas celdas — un pegado o un
relleno de columna te entrega un rango de varias celdas, así que el código que da por
hecho que Target.Value es un único valor fallará o se comportará mal; o bien recorres
Target con un bucle, o bien lo restringes con If Target.Count > 1 Then Exit Sub
cuando de verdad quieres ediciones de una sola celda. Y reacciona a la intersección,
no a todo Target, cuando un pegado abarca a la vez tu rango vigilado y celdas fuera de
él.
La distinción que hace tropezar a la gente: ignora los recálculos de fórmulas
Worksheet_Change se dispara ante un cambio en el contenido de una celda — un valor
tecleado, un valor pegado, un borrado, una escritura de VBA. No se dispara cuando
una celda simplemente muestra un número nuevo porque una fórmula se recalculó. Si C1
es =A1+B1 y A1 cambia, el evento se dispara por A1 (la celda editada), no por C1
(la recalculada).
Cuando necesitas reaccionar a que cambie un resultado, eso es un evento distinto
—Worksheet_Calculate— que se dispara al recalcular pero no te da ningún Target
(tienes que inspeccionar las celdas tú mismo). Elegir el equivocado es un fallo
silencioso: tu manejador sencillamente nunca se ejecuta. La regla: Change = alguien
editó la celda; Calculate = la salida de una fórmula se movió.
Worksheet_Change es una mitad de la pareja «reacciona al usuario». Su hermano,
Worksheet_SelectionChange, se dispara cuando el
cursor se mueve en lugar de cuando cambia un valor — y ambos pertenecen a la misma
familia de eventos que Workbook_Open, el evento que se
ejecuta cuando el archivo se abre por primera vez.
Cómo ayuda ExcelMaster
Una macro que reacciona a ediciones es engañosamente delicada: el objeto correcto,
Intersect para acotarla, EnableEvents para evitar el bucle, un manejador de errores
para que un fallo no mate todos los eventos de Excel. Sáltate el par de EnableEvents y
congelas el archivo; sáltate el manejador de errores y rompes los eventos en silencio.
ExcelMaster
te deja enunciar el comportamiento en su lugar. Di «cuando alguien edite la columna B,
pon la hora actual en la columna C, justo al lado», y escribe un Worksheet_Change en
el objeto de hoja correcto — acotado con Intersect, protegido con EnableEvents,
envuelto para que un error no pueda dejar los eventos atascados en apagado. Te quedas
con la hoja y el código; te ahorras el ritual único de congelar tu propio libro para
aprender la regla.
Preguntas frecuentes
¿Por qué mi Worksheet_Change provoca un bucle infinito o se congela?
Porque tu manejador escribe en una celda, y esa escritura es en sí misma un cambio que
vuelve a disparar Worksheet_Change — sin fin. Envuelve cada escritura con
Application.EnableEvents = False antes y Application.EnableEvents = True después, y
vuelve a activarlos siempre en un manejador de errores para que un fallo no pueda dejar
los eventos apagados.
¿Cómo hago que Worksheet_Change se ejecute solo cuando cambia una columna concreta?
Usa Intersect al principio del manejador:
If Intersect(Target, Range("B:B")) Is Nothing Then Exit Sub. Eso sale de inmediato a
menos que la edición haya tocado la columna B. Intersect devuelve el solapamiento
entre el rango editado y el rango que te importa, o Nothing cuando no hay solapamiento.
¿Se dispara Worksheet_Change cuando se recalcula una fórmula?
No. Solo se dispara cuando se edita el contenido de una celda — tecleado, pegado,
borrado o escrito por VBA. Una celda que muestra un valor nuevo porque una fórmula se
recalculó no lo activa. Para eso, usa el evento Worksheet_Calculate, que se dispara al
recalcular pero no te da un Target.
¿Dónde va el código de Worksheet_Change?
En el módulo de código de la hoja concreta — haz doble clic en la hoja (p. ej. Sheet1)
bajo «Objetos de Microsoft Excel» en el Explorador de proyectos y pon ahí
Private Sub Worksheet_Change(ByVal Target As Range). No funciona desde un Module
estándar. Para todas las hojas a la vez, usa Workbook_SheetChange en ThisWorkbook.
Mis eventos de VBA dejaron de funcionar — ¿cómo lo arreglo?
Probablemente un manejador anterior puso Application.EnableEvents = False y falló antes
de restaurarlo, dejando los eventos apagados de forma global. Escribe
Application.EnableEvents = True en la ventana Inmediato (Ctrl+G) y pulsa Enter, o
reinicia Excel. Evítalo volviendo a activar siempre los eventos en un manejador de
errores.
Probado en
Probado en: Excel 365 (Windows 11), VBA 7.1 — última verificación el 02/08/2026.
Guías relacionadas: VBA Worksheet_SelectionChange · VBA Workbook_Open · VBA On Error · VBA Range · VBA Bucle For
