Migración de la funcionalidad del ciclo de vida de la aplicación

Este tema contiene instrucciones de migración en el área de ciclo de vida de la aplicación.

API importantes

Resumen de las API y/o diferencias en las características

Las aplicaciones de la Plataforma universal de Windows (UWP) son de instancia única de forma predeterminada. Las aplicaciones del SDK de aplicaciones de Windows (WinUI 3) tienen instancias múltiples de forma predeterminada.

Una aplicación para UWP tiene métodos App como OnFileActivated, OnSearchActivated, OnActivated y OnBackgroundActivated que indican implícitamente cómo se activó la aplicación. En una aplicación del SDK de Aplicaciones para Windows, en App.OnLaunched (o en cualquier método), llame a (AppInstance.GetActivatedEventArgs) para recuperar los argumentos de eventos activados y compruebe cómo se activó la aplicación.

Consulte también la fila tareas en segundo plano de la tabla del tema ¿Qué se admite al migrar de UWP a WinUI 3?

Aplicaciones de instancia única

Las aplicaciones de la Plataforma universal de Windows (UWP) se encuentran de forma predeterminada en instancias únicas (puedes optar por admitir varias instancias; consulte Creación de una aplicación para UWP de varias instancias).

Por lo tanto, el comportamiento de una aplicación para UWP de instancia única es que la segunda vez (y las siguientes) que se inicia, se activa la instancia actual. Supongamos, por ejemplo, que en su aplicación para UWP ha implementado la característica de asociación de tipos de archivo. Si desde el Explorador de archivos abre un archivo (del tipo para el que la aplicación ha registrado una asociación de tipos de archivo) y la aplicación ya se está ejecutando, se activa esa instancia que ya se está ejecutando.

Las aplicaciones del SDK de Aplicaciones de Windows (WinUI 3), por otro lado, son instancias múltiples de forma predeterminada. Por lo tanto, de forma predeterminada, la segunda vez (y las siguientes) que inicie una aplicación del SDK de Aplicaciones de Windows (WinUI 3), se iniciará una nueva instancia de la aplicación. Si, por ejemplo, una aplicación del SDK de Aplicaciones para Windows (WinUI 3) implementa la asociación de tipos de archivo y desde el Explorador de archivos se abre un archivo (del tipo correcto) mientras esa aplicación ya se está ejecutando, se inicia una nueva instancia de la aplicación de forma predeterminada.

Si quieres que su aplicación del SDK de Aplicaciones para Windows (WinUI 3) sea de instancia única, como la aplicación para UWP, puede invalidar el comportamiento predeterminado descrito anteriormente. Usará AppInstance.FindOrRegisterForKey y AppInstance.IsCurrent para determinar si la instancia actual es la instancia principal. Si no es así, llamará a AppInstance.RedirectActivationToAsync para redirigir la activación a la instancia principal que ya se está ejecutando y, a continuación, salir de la instancia actual (sin crear ni activar su ventana principal).

Para obtener más información, consulte Creación de instancias de aplicaciones con la API del ciclo de vida de la aplicación.

Importante

El código que se muestra a continuación funciona según lo esperado siempre que tenga como destino la arquitectura x64. Esto se aplica tanto a C# como a C++/WinRT.

Creación de instancias únicas en Main o wWinMain

Es mejor comprobar si es necesario redirigir la activación lo antes posible en la ejecución de la aplicación. Por ese motivo, se recomienda realizar la lógica de creación de instancias únicas en la función Main (o wWinMain para C++/WinRT) de la aplicación. En esta sección se muestra cómo hacerlo.

Normalmente, la función Main de la aplicación se genera automáticamente por el sistema de compilación y se coloca en un archivo oculto. Por lo tanto, el primer paso es configurar el proyecto para que no genere automáticamente esa función. Para ello, defina el símbolo DISABLE_XAML_GENERATED_MAIN en las Propiedades del proyecto.

Instrucciones para C#

Vaya a Propiedades> (seleccione Todas las configuraciones y Todas las plataformas) >Compilar>Símbolos de compilación condicional y pegue el símbolo DISABLE_XAML_GENERATED_MAIN.

Dado que acabamos de impedir que el proyecto genere automáticamente una función Main, el proyecto no se compilará en este momento. Por lo tanto, el segundo y último paso es implementar nuestra propia versión de esa función en un archivo de código fuente.

Agregue un nuevo elemento de proyecto de tipo Class al proyecto y asígnele el nombre Program.cs. Dentro de Program.cs, reemplace el código class Program {} por su propia implementación. Para obtener un ejemplo del código que se va a usar, consulte Program.cs en el Ejemplo de AppLifecycle.

Instrucciones para C++/WinRT

Vaya a propiedades> (seleccione Todas las configuraciones y Todas las plataformas) >Propiedades de configuración>C/C++>Preprocesador>Definiciones de preprocesador, Editar el valor y agregar el símbolo DISABLE_XAML_GENERATED_MAIN.

Dado que acabamos de impedir que el proyecto genere automáticamente una función wWinMain, el proyecto no se compilará en este momento. Por lo tanto, el segundo y último paso es implementar nuestra propia versión de esa función en un archivo de código fuente.

Agregue una referencia al paquete NuGet Microsoft.Windows.ImplementationLibrary y actualice los archivos de código fuente pch.h y App.xaml.cpp del proyecto. Para obtener un ejemplo del código que se va a usar, consulte el Ejemplo de AppLifecycle. Asegúrese de cambiar el espacio de nombres en winrt::CppWinUiDesktopInstancing::implementation::App para que se adapte a su proyecto concreto).

Para resolver el "error C2872: "Microsoft": símbolo ambiguo", cambie using namespace Microsoft::UI::Xaml; a using namespace winrt::Microsoft::UI::Xaml;. Y realice cambios adicionales similares a las directivas using.

Creación de instancias únicas en Application.OnLaunched

Una alternativa al uso de Main o wWinMain consiste en realizar la lógica de creación de instancias únicas en el método Application.OnLaunched de la clase App.

Importante

Realizar este trabajo en Application.OnLaunched puede simplificar la aplicación. Sin embargo, muchas cosas dependen de lo que haga la aplicación. Si va a terminar redirigiendo, y luego finalizando la instancia actual, entonces querrá evitar hacer cualquier trabajo desechable (o incluso trabajo que necesite deshacerse explícitamente). En casos como ese, Application.OnLaunched podría ser demasiado tarde y es posible que prefiera hacer el trabajo en la función Main o wWinMain de la aplicación.

// App.xaml.cs in a Windows App SDK (WinUI 3) app
...
protected override async void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    // If this is the first instance launched, then register it as the "main" instance.
    // If this isn't the first instance launched, then "main" will already be registered,
    // so retrieve it.
    var mainInstance = Microsoft.Windows.AppLifecycle.AppInstance.FindOrRegisterForKey("main");

    // If the instance that's executing the OnLaunched handler right now
    // isn't the "main" instance.
    if (!mainInstance.IsCurrent)
    {
        // Redirect the activation (and args) to the "main" instance, and exit.
        var activatedEventArgs =
            Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
        await mainInstance.RedirectActivationToAsync(activatedEventArgs);
        System.Diagnostics.Process.GetCurrentProcess().Kill();
        return;
    }

    m_window = new MainWindow();
    m_window.Activate();
}
// pch.h in a Windows App SDK (WinUI 3) app
...
#include <winrt/Microsoft.Windows.AppLifecycle.h>
...

// App.xaml.h
...
struct App : AppT<App>
{
    ...
    winrt::fire_and_forget OnLaunched(Microsoft::UI::Xaml::LaunchActivatedEventArgs const&);
    ...
}

// App.xaml.cpp
...
using namespace winrt;
using namespace Microsoft::Windows::AppLifecycle;
...
winrt::fire_and_forget App::OnLaunched(LaunchActivatedEventArgs const&)
{
    // If this is the first instance launched, then register it as the "main" instance.
    // If this isn't the first instance launched, then "main" will already be registered,
    // so retrieve it.
    auto mainInstance{ AppInstance::FindOrRegisterForKey(L"main") };

    // If the instance that's executing the OnLaunched handler right now
    // isn't the "main" instance.
    if (!mainInstance.IsCurrent())
    {
        // Redirect the activation (and args) to the "main" instance, and exit.
        auto activatedEventArgs{ AppInstance::GetCurrent().GetActivatedEventArgs() };
        co_await mainInstance.RedirectActivationToAsync(activatedEventArgs);
        ::ExitProcess(0);
        co_return;
    }

    window = make<MainWindow>();
    window.Activate();
}

Como alternativa, puede llamar a AppInstance.GetInstances para recuperar una colección de objetos AppInstance en ejecución. Si el número de elementos de esa colección es mayor que 1, la instancia principal ya se está ejecutando y debe redirigir a eso.

Asociación de tipo de archivo

En un proyecto del SDK de Aplicaciones para Windows, para especificar el punto de extensión de una asociación de tipo de archivo, realice la misma configuración en el archivo Package.appxmanifest que la que haría para un proyecto de UWP. Esta es la configuración.

Abierto Package.appxmanifest. En Declaraciones, elija Asociaciones de tipo de archivo y haga clic en Agregar. Configure las siguientes propiedades.

Nombre para mostrar: MyFile Name: myfile File type: .myf

Para registrar la asociación de tipo de archivo, compile la aplicación, iníciela y ciérrela.

La diferencia radica en el código imperativo. En una aplicación para UWP, implementa App::OnFileActivated para controlar la activación de archivos. Pero en una aplicación del SDK de Aplicaciones para Windows, escribe código en App::OnLaunched para comprobar el tipo de activación extendida (ExtendedActivationKind) del argumento de evento activado (AppInstance.GetActivatedEventArgs) y ver si la activación es una activación de archivo.

Nota:

No use el objeto Microsoft.UI.Xaml.LaunchActivatedEventArgs pasado a App::OnLaunched para determinar el tipo de activación, ya que notifica "Launch" incondicionalmente.

Si la aplicación tiene navegación, ya tendrá código de navegación en App::OnLaunchedy es posible que quiera volver a usar esa lógica. Para obtener más información, consulte ¿Es necesario implementar la navegación de páginas?

// App.xaml.cs in a Windows App SDK app
...
using Microsoft.Windows.AppLifecycle;
...
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    var activatedEventArgs = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
    if (activatedEventArgs.Kind == Microsoft.Windows.AppLifecycle.ExtendedActivationKind.File)
    {
        ...
    }
    ...
}
// pch.h in a Windows App SDK app
...
#include <winrt/Microsoft.Windows.AppLifecycle.h>

// App.xaml.cpp
...
using namespace Microsoft::Windows::AppLifecycle;
...
void App::OnLaunched(LaunchActivatedEventArgs const&)
{
    auto activatedEventArgs{ AppInstance::GetCurrent().GetActivatedEventArgs() };
    if (activatedEventArgs.Kind() == ExtendedActivationKind::File)
    {
        ...
    }
    ...
}

OnActivated, OnBackgroundActivated y otros métodos de control de activación

En una aplicación para UWP, para invalidar los distintos medios por los que se puede activar la aplicación, puede invalidar los métodos correspondientes en su clase App, comoOnFileActivated, OnSearchActivated o el OnActivated.

En una aplicación del SDK de Aplicaciones para Windows, en App.OnLaunched (o de hecho en cualquier momento) puede llamar a (AppInstance.GetActivatedEventArgs) para recuperar los argumentos de eventos activados y comprobar cómo se activó la aplicación.

Consulte la sección Asociación de tipos de archivo anterior para obtener más información y un ejemplo de código. Puede aplicar la misma técnica para cualquier tipo de activación especificado por la enumeración ExtendedActivationKind.