Ciclo de vida de la aplicación
Las aplicaciones de interfaz de usuario de aplicaciones multiplataforma de .NET (.NET MAUI) suelen tener cuatro estados de ejecución: no en ejecución, en ejecución, desactivados y detenidos. .NET MAUI genera eventos de ciclo de vida multiplataforma en la Window clase cuando una aplicación pasa del estado no en ejecución al estado en ejecución, el estado en ejecución al estado desactivado, el estado desactivado al estado detenido, el estado detenido al estado en ejecución y el estado detenido al estado no en ejecución.
En el diagrama siguiente se muestra información general sobre el ciclo de vida de la aplicación MAUI de .NET:
En el diagrama, el óvalo gris indica que la aplicación no se carga en la memoria. Los óvalos azules claros indican que la aplicación está en memoria. El texto de los arcos indica los eventos generados por .NET MAUI, que proporcionan notificaciones a la aplicación en ejecución.
El estado de ejecución de una aplicación depende del historial de la aplicación. Por ejemplo, cuando se instala una aplicación por primera vez o se inicia un dispositivo, se puede considerar que la aplicación no se está ejecutando. Cuando se inicia la aplicación, se generan los Created eventos y Activated y la aplicación se ejecuta. Si una ventana de aplicación diferente obtiene el foco, se genera el Deactivated evento y se desactiva la aplicación. Si el usuario cambia a otra aplicación o vuelve a la pantalla inicio del dispositivo, de modo que la ventana de la aplicación ya no esté visible, se generan los Deactivated eventos y Stopped y la aplicación se detiene. Si el usuario vuelve a la aplicación, se genera el Resuming evento y se ejecuta la aplicación. Como alternativa, un usuario podría terminar una aplicación mientras se ejecuta. En esta situación, la aplicación se desactiva y , a continuación, se detiene, se genera el Destroying evento y la aplicación no se está ejecutando. Del mismo modo, un dispositivo podría finalizar una aplicación mientras se detiene, debido a restricciones de recursos y se genera el Destroying evento y la aplicación no se está ejecutando.
Además, .NET MAUI permite que las aplicaciones se notifiquen cuando se generen eventos de ciclo de vida de la plataforma. Para más información, consulte Eventos del ciclo de vida de la plataforma.
Eventos de ciclo de vida multiplataforma
La Window clase define los siguientes eventos de ciclo de vida multiplataforma:
| evento | Descripción | Acción que realizar |
|---|---|---|
Created |
Este evento se genera después de crear la ventana nativa. En este momento, la ventana multiplataforma tendrá un controlador de ventana nativo, pero es posible que la ventana aún no esté visible. | |
Activated |
Este evento se genera cuando se ha activado la ventana y es, o se convertirá, en la ventana centrada. | |
Deactivated |
Este evento se genera cuando la ventana ya no es la ventana centrada. Sin embargo, es posible que la ventana siga siendo visible. | |
Stopped |
Este evento se genera cuando la ventana ya no está visible. No hay ninguna garantía de que una aplicación se reanude desde este estado, ya que el sistema operativo puede terminar. | Desconecte de los procesos de larga duración o cancele las solicitudes pendientes que puedan consumir recursos del dispositivo. |
Resumed |
Este evento se genera cuando una aplicación se reanuda después de detenerse. Este evento no se generará la primera vez que se inicie la aplicación y solo se puede generar si el Stopped evento se ha generado anteriormente. |
Suscríbase a los eventos necesarios y actualice cualquier contenido que esté en la página visible. |
Destroying |
Este evento se genera cuando se destruye y desasigna la ventana nativa. Es posible que se use la misma ventana multiplataforma en una nueva ventana nativa cuando se vuelva a abrir la aplicación. | Quite todas las suscripciones de eventos que haya asociado a la ventana nativa. |
Estos eventos multiplataforma se asignan a diferentes eventos de plataforma y en la tabla siguiente se muestra esta asignación:
| evento | Android | iOS | Windows |
|---|---|---|---|
Created |
OnPostCreate |
FinishedLaunching |
Created |
Activated |
OnResume |
OnActivated |
Activated (CodeActivated y PointerActivated) |
Deactivated |
OnPause |
OnResignActivation |
Activated (Deactivated) |
Stopped |
OnStop |
DidEnterBackground |
VisibilityChanged |
Resumed |
OnRestart |
WillEnterForeground |
Resumed |
Destroying |
OnDestroy |
WillTerminate |
Closed |
Además de estos eventos, la Window clase también tiene los siguientes métodos reemplazables:
OnCreated, que se invoca cuando se genera elCreatedevento .OnActivated, que se invoca cuando se genera elActivatedevento .OnDeactivated, que se invoca cuando se genera elDeactivatedevento .OnStopped, que se invoca cuando se genera elStoppedevento .OnResumed, que se invoca cuando se genera elResumedevento .OnDestroying, que se invoca cuando se genera elDestroyingevento .
Para suscribirse a los eventos del Window ciclo de vida, invalide el CreateWindow método de la App clase para crear una Window instancia en la que puede suscribirse a eventos:
namespace MyMauiApp
{
public partial class App : Application
{
public App()
{
InitializeComponent();
MainPage = new MainPage();
}
protected override Window CreateWindow(IActivationState activationState)
{
Window window = base.CreateWindow(activationState);
window.Created += (s, e) =>
{
// Custom logic
};
return window;
}
}
}
Como alternativa, para consumir las invalidaciones del ciclo de vida, cree una clase que derive de la Window clase .
namespace MyMauiApp
{
public class MyWindow : Window
{
public MyWindow() : base()
{
}
public MyWindow(Page page) : base(page)
{
}
protected override void OnCreated()
{
// Register services
}
}
}
La Windowclase derivada de se puede consumir reemplazando el CreateWindow método de la App clase para devolver una MyWindow instancia.
Advertencia
Se producirá una InvalidOperationException excepción si la App.MainPage propiedad se establece y el CreateWindow método crea un Window objeto mediante la invalidación que acepta un Page argumento.
Eventos del ciclo de vida de la plataforma
.NET MAUI define delegados que se invocan en respuesta a los eventos del ciclo de vida de la plataforma que se generan. Los controladores se pueden especificar para estos delegados, mediante métodos con nombre o funciones anónimas, que se ejecutan cuando se invoca el delegado. Este mecanismo permite a las aplicaciones recibir notificaciones cuando se generan eventos comunes del ciclo de vida de la plataforma.
Importante
El ConfigureLifecycleEvents método está en el Microsoft.Maui.LifecycleEvents espacio de nombres .
Android
En la tabla siguiente se enumeran los delegados MAUI de .NET que se invocan en respuesta a los eventos de ciclo de vida de Android que se generan:
| Delegado | Argumentos | Descripción | Comentarios |
|---|---|---|---|
OnActivityResult |
Android.App.Activity, int, Android.App.Result, Android.Content.Intent? |
Se invoca cuando se cierra una actividad iniciada. | |
OnApplicationConfigurationChanged |
Android.App.Application, Android.Content.Res.Configuration |
Se invoca cuando cambia la configuración del dispositivo mientras se ejecuta el componente. | |
OnApplicationCreate |
Android.App.Application |
Se invoca cuando se ha iniciado la aplicación, antes de que se hayan creado objetos activity, service o receiver (excepto los proveedores de contenido). | |
OnApplicationCreating |
Android.App.Application |
Se invoca cuando se inicia la aplicación, antes de que se hayan creado objetos activity, service o receiver (excepto los proveedores de contenido). | |
OnApplicationLowMemory |
Android.App.Application |
Se invoca cuando el sistema se está ejecutando poco en la memoria y los procesos que se ejecutan activamente deben recortar su uso de memoria. | |
OnApplicationTrimMemory |
Android.App.Application, Android.Content.TrimMemory |
Se invoca cuando el sistema operativo ha determinado que es un buen momento para que un proceso recorte la memoria innecesaria de su proceso. | |
OnBackPressed |
Android.App.Activity |
Se invoca cuando la actividad ha detectado una pulsación de la tecla Atrás. | |
OnConfigurationChanged |
Android.App.Activity, Android.Content.Res.Configuration |
Se invoca cuando cambia la configuración del dispositivo mientras se ejecuta la actividad. | |
OnCreate |
Android.App.Activity, Android.OS.Bundle? |
Se genera cuando se crea la actividad. | |
OnDestroy |
Android.App.Activity |
Se invoca cuando finaliza la actividad o porque el sistema destruye temporalmente la instancia de actividad para ahorrar espacio. | Llame siempre a la implementación de la superclase. |
OnNewIntent |
Android.App.Activity, Android.Content.Intent? |
Se invoca cuando se vuelve a iniciar la actividad mientras se encuentra en la parte superior de la pila de actividad en lugar de una nueva instancia de la actividad que se está iniciando. | |
OnPause |
Android.App.Activity |
Se invoca cuando una actividad está en segundo plano, pero aún no se ha matado. | Llame siempre a la implementación de la superclase. |
OnPostCreate |
Android.App.Activity, Android.OS.Bundle? |
Se invoca cuando se completa el inicio de la actividad, después OnStart de llamar a y OnRestoreInstanceState . |
Llame siempre a la implementación de la superclase. Se trata de un evento solo del sistema que, por lo general, las aplicaciones no deben usar. |
OnPostResume |
Android.App.Activity |
Se invoca cuando se completa la reanudación de la actividad, después OnResume de llamar a . |
Llame siempre a la implementación de la superclase. Se trata de un evento solo del sistema que, por lo general, las aplicaciones no deben usar. |
OnRequestPermissionsResult |
Android.App.Activity, int, string[], Android.Content.PM.Permission[] |
Se invoca como devolución de llamada para el resultado de solicitar permisos. | |
OnRestart |
Android.App.Activity |
Se invoca después de OnStop que se vuelva a mostrar la actividad actual al usuario (el usuario ha vuelto a ella). |
Llame siempre a la implementación de la superclase. |
OnRestoreInstanceState |
Android.App.Activity, Android.OS.Bundle |
Se invoca después de OnStart que se reinicialice la actividad desde un estado guardado previamente. |
|
OnResume |
Android.App.Activity |
Se invoca después OnRestoreInstanceStatede , OnRestarto OnPause, para indicar que la actividad está activa y está lista para recibir la entrada. |
|
OnSaveInstanceState |
Android.App.Activity, Android.OS.Bundle |
Se invoca para recuperar el estado por instancia de una actividad que se está eliminando para que el estado se pueda restaurar en OnCreate o OnRestoreInstanceState. |
|
OnStart |
Android.App.Activity |
Se invoca después OnCreate de o OnRestart cuando se ha detenido la actividad, pero ahora se muestra al usuario. |
Llame siempre a la implementación de la superclase. |
OnStop |
Android.App.Activity |
Se invoca cuando la actividad ya no es visible para el usuario. | Llame siempre a la implementación de la superclase. |
Importante
Cada delegado tiene un método de extensión con el mismo nombre correspondiente, al que se puede llamar para registrar un controlador para el delegado.
Para responder a un delegado de ciclo de vida de Android que se invoca, llame al ConfigureLifecycleEvents método en el MauiAppBuilder objeto del método de la CreateMauiappMauiProgram clase . A continuación, en el ILifecycleBuilder objeto , llame al AddAndroid método y especifique que Action registra los controladores para los delegados necesarios:
using Microsoft.Maui.LifecycleEvents;
namespace PlatformLifecycleDemo
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureLifecycleEvents(events =>
{
#if ANDROID
events.AddAndroid(android => android
.OnActivityResult((activity, requestCode, resultCode, data) => LogEvent("OnActivityResult", requestCode.ToString()))
.OnStart((activity) => LogEvent("OnStart"))
.OnCreate((activity, bundle) => LogEvent("OnCreate"))
.OnBackPressed((activity) => LogEvent("OnBackPressed"))
.OnStop((activity) => LogEvent("OnStop")));
#endif
static void LogEvent(string eventName, string type = null)
{
System.Diagnostics.Debug.WriteLine($"Lifecycle event: {eventName}{(type == null ? string.Empty : $" ({type})")}");
}
});
return builder.Build();
}
}
}
Para obtener más información sobre el ciclo de vida de la aplicación Android, consulte Descripción del ciclo de vida de la actividad en developer.android.com.
iOS
En la tabla siguiente se enumeran los delegados MAUI de .NET que se invocan en respuesta a los eventos de ciclo de vida de iOS que se generan:
| Delegado | Argumentos | Descripción |
|---|---|---|
ContinueUserActivity |
UIKit.UIApplication, Foundation.NSUserActivity, UIKit.UIApplicationRestorationHandler |
Se invoca cuando la aplicación recibe datos asociados a una actividad de usuario, como transferir una actividad desde un dispositivo diferente mediante Handoff. |
DidEnterBackground |
UIKit.UIApplication |
Se invoca cuando la aplicación ha entrado en segundo plano. |
FinishedLaunching |
UIKit.UIApplication, Foundation.NSDictionary |
Se invoca cuando se ha iniciado la aplicación. |
OnActivated |
UIKit.UIApplication |
Se invoca cuando se inicia la aplicación y cada vez que la aplicación vuelve al primer plano. |
OnResignActivation |
UIKit.UIApplication |
Se invoca cuando la aplicación está a punto de entrar en segundo plano, suspenderse o cuando el usuario recibe una interrupción, como una llamada telefónica o un texto. |
OpenUrl |
UIKit.UIApplication, Foundation.NSDictionary |
Se invoca cuando la aplicación debe abrir una dirección URL especificada. |
PerformActionForShortcutItem |
UIKit.UIApplication, UIKit.UIApplicationShortcutItem, UIKit.UIOperationHandler |
Se invoca cuando se inicia una acción rápida de pantalla principal. |
WillEnterForeground |
UIKit.UIApplication |
Se invoca si la aplicación devolverá un estado en segundo plano. |
WillFinishLaunching |
UIKit.UIApplication, Foundation.NSDictionary |
Se invoca cuando se ha iniciado el inicio de la aplicación, pero aún no se ha producido la restauración del estado. |
WillTerminate |
UIKit.UIApplication |
Se invoca si la aplicación finaliza debido a restricciones de memoria o directamente por el usuario. |
Importante
Cada delegado tiene un método de extensión con el mismo nombre correspondiente, al que se puede llamar para registrar un controlador para el delegado.
Para responder a un delegado de ciclo de vida de iOS que se invoca, llame al ConfigureLifecycleEvents método en el MauiAppBuilder objeto del método de MauiProgram la CreateMauiapp clase . A continuación, en el ILifecycleBuilder objeto , llame al AddiOS método y especifique que Action registra los controladores para los delegados necesarios:
using Microsoft.Maui.LifecycleEvents;
namespace PlatformLifecycleDemo
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureLifecycleEvents(events =>
{
#if IOS
events.AddiOS(ios => ios
.OnActivated((app) => LogEvent("OnActivated"))
.OnResignActivation((app) => LogEvent("OnResignActivation"))
.DidEnterBackground((app) => LogEvent("DidEnterBackground"))
.WillTerminate((app) => LogEvent("WillTerminate")));
#endif
static void LogEvent(string eventName, string type = null)
{
System.Diagnostics.Debug.WriteLine($"Lifecycle event: {eventName}{(type == null ? string.Empty : $" ({type})")}");
}
});
return builder.Build();
}
}
}
Para obtener más información sobre el ciclo de vida de la aplicación de iOS, consulte Administración del ciclo de vida de la aplicación en developer.apple.com.
Windows
En la tabla siguiente se enumeran los delegados MAUI de .NET que se invocan en respuesta a los eventos de ciclo de vida de Windows que se generan:
| Delegado | Argumentos | Descripción |
|---|---|---|
OnActivated |
Microsoft.UI.Xaml.Window, Microsoft.UI.Xaml.WindowActivatedEventArgs |
Se invoca cuando se genera el evento de plataforma Activated , si la aplicación no se reanuda. |
OnClosed |
Microsoft.UI.Xaml.Window, Microsoft.UI.Xaml.WindowEventArgs |
Se invoca cuando se genera el evento de plataforma Closed . |
OnLaunched |
Microsoft.UI.Xaml.Window, Microsoft.UI.Xaml.LaunchActivatedEventArgs |
Invocado por la invalidación de MAUI de Application.OnLaunched .NET una vez creada y activada la ventana nativa. |
OnLaunching |
Microsoft.UI.Xaml.Window, Microsoft.UI.Xaml.LaunchActivatedEventArgs |
Invocado por la invalidación de MAUI de Application.OnLaunched .NET antes de que se haya creado y activado la ventana nativa. |
OnPlatformMessage |
Microsoft.UI.Xaml.Window, WindowsPlatformMessageEventArgs |
Se invoca cuando .NET MAUI recibe mensajes nativos específicos de Windows. |
OnPlatformWindowSubclassed |
Microsoft.UI.Xaml.Window, WindowsPlatformWindowSubclassedEventArgs |
Invocado por MAUI de .NET cuando la ventana Win32 está subclase. |
OnResumed |
Microsoft.UI.Xaml.Window |
Se invoca cuando se genera el evento de plataforma Activated , si la aplicación se reanuda. |
OnVisibilityChanged |
Microsoft.UI.Xaml.Window, Microsoft.UI.Xaml.WindowVisibilityChangedEventArgs |
Se invoca cuando se genera el evento de plataforma VisibilityChanged . |
OnWindowCreated |
Microsoft.UI.Xaml.Window |
Se invoca cuando se crea la ventana nativa para la plataforma Windowmultiplataforma . |
.NET MAUI expone mensajes nativos específicos de Windows como un evento de ciclo de vida con el OnPlatformMessage delegado. El WindowsPlatformMessageEventArgs objeto que acompaña a este delegado incluye una MessageId propiedad de tipo uint. El valor de esta propiedad se puede examinar para determinar qué mensaje se ha pasado a la ventana de la aplicación. Para obtener más información sobre los mensajes de Windows, vea Mensajes de Windows (Introducción a Win32 y C++). Para obtener una lista de constantes de mensajes de ventana, consulte Notificaciones de ventana.
Importante
Cada delegado tiene un método de extensión con el mismo nombre correspondiente, al que se puede llamar para registrar un controlador para el delegado.
Para responder a un delegado de ciclo de vida de Windows que se invoca, llame al ConfigureLifecycleEvents método en el MauiAppBuilder objeto del método de la CreateMauiAppMauiProgram clase . A continuación, en el ILifecycleBuilder objeto , llame al AddWindows método y especifique que Action registra los controladores para los delegados necesarios:
using Microsoft.Maui.LifecycleEvents;
namespace PlatformLifecycleDemo
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureLifecycleEvents(events =>
{
#if WINDOWS
events.AddWindows(windows => windows
.OnActivated((window, args) => LogEvent("OnActivated"))
.OnClosed((window, args) => LogEvent("OnClosed"))
.OnLaunched((window, args) => LogEvent("OnLaunched"))
.OnLaunching((window, args) => LogEvent("OnLaunching"))
.OnVisibilityChanged((window, args) => LogEvent("OnVisibilityChanged"))
.OnPlatformMessage((window, args) =>
{
if (args.MessageId == Convert.ToUInt32("0x02E0"))
{
// DPI has changed
}
}));
#endif
static void LogEvent(string eventName, string type = null)
{
System.Diagnostics.Debug.WriteLine($"Lifecycle event: {eventName}{(type == null ? string.Empty : $" ({type})")}");
}
});
return builder.Build();
}
}
}
Recuperar el objeto Window
El código de la plataforma puede recuperar el objeto de la aplicación de los eventos del Window ciclo de vida de la plataforma, con el método de GetWindow extensión :
using Microsoft.Maui.LifecycleEvents;
namespace PlatformLifecycleDemo
{
public static class MauiProgram
{
public static MauiApp CreateMauiApp()
{
var builder = MauiApp.CreateBuilder();
builder
.UseMauiApp<App>()
.ConfigureLifecycleEvents(events =>
{
#if WINDOWS
events.AddWindows(windows => windows
.OnClosed((window, args) =>
{
IWindow appWindow = window.GetWindow();
}));
#endif
});
return builder.Build();
}
}
}
Eventos de ciclo de vida personalizados
Aunque .NET MAUI define delegados que se invocan en respuesta a los eventos del ciclo de vida de la plataforma que se generan, solo expone un conjunto común de eventos de ciclo de vida de la plataforma. Sin embargo, también incluye un mecanismo, normalmente para los autores de bibliotecas, que permite recibir notificaciones a las aplicaciones cuando se generan eventos adicionales del ciclo de vida de la plataforma. El proceso para llevarlo a cabo es el siguiente:
- Registre un controlador de eventos para un evento de ciclo de vida de la plataforma que no expone .NET MAUI.
- En el controlador de eventos para el evento de ciclo de vida de la plataforma, recupere la
ILifecycleEventServiceinstancia y llame a suInvokeEventsmétodo, especificando el nombre del evento de plataforma como su argumento.
A continuación, las aplicaciones que quieran recibir la notificación del evento de ciclo de vida de la plataforma deben modificar el CreateMauiApp método de su MauiProgram clase para llamar al ConfigureLifecycleEvents método en el MauiAppBuilder objeto . A continuación, en el ILifecycleBuilder objeto , llame al AddEvent método y especifique el nombre del evento de plataforma y el Action que se invocará cuando se genere el evento de plataforma.
Ejemplo
El evento WinUI 3 Window.SizeChanged se produce cuando la ventana de la aplicación nativa se ha representado por primera vez o ha cambiado su tamaño de representación. .NET MAUI no expone este evento de plataforma como evento de ciclo de vida. Sin embargo, las aplicaciones pueden recibir notificaciones cuando se genera este evento de plataforma mediante el siguiente enfoque:
Registre un controlador de eventos para el evento de ciclo de vida de la Window.SizeChanged plataforma:
using Microsoft.Maui.LifecycleEvents; ... public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureLifecycleEvents(events => { #if WINDOWS events.AddWindows(windows => windows .OnWindowCreated(window => { window.SizeChanged += OnSizeChanged; })); #endif }); return builder.Build(); }En el controlador de eventos para el evento de ciclo de vida de la plataforma, recupere la
ILifecycleEventServiceinstancia y llame a suInvokeEventsmétodo, especificando el nombre del evento de plataforma como su argumento:using Microsoft.Maui.LifecycleEvents; ... #if WINDOWS static void OnSizeChanged(object sender, Microsoft.UI.Xaml.WindowSizeChangedEventArgs args) { ILifecycleEventService service = MauiWinUIApplication.Current.Services.GetRequiredService<ILifecycleEventService>(); service.InvokeEvents(nameof(Microsoft.UI.Xaml.Window.SizeChanged)); } #endifEl
MauiWinUIApplicationtipo en Windows se puede usar para acceder a la instancia de aplicación nativa a través de suCurrentpropiedad . ElMauiApplicationtipo en Android se puede usar para acceder a la instancia de aplicación nativa. Del mismo modo, elMauiUIApplicationDelegatetipo de iOS se puede usar para acceder a la instancia de aplicación nativa.Advertencia
Al invocar un evento no registrado, con el
InvokeEventsmétodo , no se produce una excepción.En el
CreateMauiAppmétodo de laMauiProgramclase , llame alConfigureLifecycleEventsmétodo en elMauiAppBuilderobjeto . A continuación, en el objeto , llame alILifecycleBuilderAddEventmétodo y especifique el nombre del evento de plataforma y elActionque se invocará cuando se genere el evento de plataforma:using Microsoft.Maui.LifecycleEvents; namespace PlatformLifecycleDemo { public static class MauiProgram { public static MauiApp CreateMauiApp() { var builder = MauiApp.CreateBuilder(); builder .UseMauiApp<App>() .ConfigureLifecycleEvents(events => { #if WINDOWS events.AddWindows(windows => windows .OnWindowCreated(window => { window.SizeChanged += OnSizeChanged; })); events.AddEvent(nameof(Microsoft.UI.Xaml.Window.SizeChanged), () => LogEvent("Window SizeChanged")); #endif static void LogEvent(string eventName, string type = null) { System.Diagnostics.Debug.WriteLine($"Lifecycle event: {eventName}{(type == null ? string.Empty : $" ({type})")}"); } }); return builder.Build(); } } }
El efecto general es que cuando un usuario cambia el tamaño de la ventana de la aplicación en Windows, se ejecuta la acción especificada en el AddEvent método .
Nota
El AddEvent método también tiene una sobrecarga que permite especificar un delegado.