应用程序生命周期功能迁移

本主题包含应用程序生命周期区域中的迁移指南。

重要的 API

API 和/或功能差异摘要

通用 Windows 平台 (UWP) 应用在默认情况下是单实例;Windows 应用 SDK (WinUI 3) 应用在默认情况下是多实例。

UWP 应用具有可隐式告知如何激活应用的 App 方法,例如 OnFileActivated、OnSearchActivated、OnActivated 和 OnBackgroundActivated;在 Windows 应用 SDK 应用中,在 App.OnLaunched 中(或任何方法)中调用 (AppInstance.GetActivatedEventArgs) 来检索已激活事件参数,并检查它们来确定应用是如何激活的。

另请参阅从 UWP 迁移到 WinUI 3 时支持的操作主题中的表中的“后台任务”行。

单实例应用

默认情况下,通用 Windows 平台 (UWP) 应用单实例(你可以选择支持多个实例 — 请参阅创建多实例 UWP 应用)。

因此,单实例 UWP 应用的行为方式是在第二次(和后续)启动时激活当前实例。 例如在 UWP 应用中,实现了文件类型关联功能。 如果从文件资源管理器打开文件(属于应用为其注册了文件类型关联的类型),并且应用已在运行,则会激活已在运行的实例。

另一方面,Windows 应用 SDK (WinUI 3) 应用在默认情况下是多实例。 因此在默认情况下,第二次(和后续)启动 Windows 应用 SDK (WinUI 3) 应用时,会启动应用的新实例。 例如,如果一个 Windows 应用 SDK (WinUI 3) 应用实现了文件类型关联,并且在该应用已在运行时从文件资源管理器打开文件(属于正确类型),则在默认情况下会启动该应用的新实例。

如果希望 Windows 应用 SDK (WinUI 3) 应用如同 UWP 应用一样是单实例,则可以替代上述默认行为。 你将使用 AppInstance.FindOrRegisterForKeyAppInstance.IsCurrent 确定当前实例是否为主实例。 如果不是,则你会调用 AppInstance.RedirectActivationToAsync,以便将激活重定向到已在运行的主实例,然后从当前实例中退出(而不创建或激活其主窗口)。

有关详细信息,请参阅应用实例化与应用生命周期 API

重要

下面显示的代码按预期方式工作,前提是面向 x64 体系结构。 这适用于 C# 和 C++/WinRT。

Main 或 wWinMain 中的单实例

最好检查是否需要在应用的执行过程中尽早重定向激活。 因此,建议在应用的 Main(对于 C++/WinRT 为 wWinMain)中执行单实例逻辑。 本部分介绍操作方式。

通常,你应用的 Main 函数由生成系统自动生成并置于隐藏文件中。 第一步是将项目配置为不自动生成该函数。 为此,请在项目“属性”中定义符号 DISABLE_XAML_GENERATED_MAIN

C# 的说明

转到“属性”(选择“所有配置”和“所有平台”)>“生成”>“条件编译符号”,然后在 DISABLE_XAML_GENERATED_MAIN 符号中粘贴。>

由于我们只是阻止了项目自动生成 Main 函数,因此项目不会在此时生成。 第二步也是最后一步是在源代码文件中实现我们自己的该函数版本。

将类型为“类”的新项目项添加到项目中,并将其命名为 Program.cs。Program.cs 中,将代码 class Program {} 替换为你自己的实现。 有关要使用的代码的示例,请参阅 AppLifecycle 示例中的 Program.cs

C++/WinRT 的说明

转到“属性”>(选择“所有配置”和“所有平台”)>“配置属性”>“C/C++”>“预处理器”>“预处理器定义”,“编辑”值,然后添加 DISABLE_XAML_GENERATED_MAIN 符号。

我们只是阻止了项目自动生成 wWinMain 函数,因此这时不会生成项目。 第二步也是最后一步是在源代码文件中实现我们自己的该函数版本。

添加对 NuGet 包 Microsoft.Windows.ImplementationLibrary 的引用,并更新项目的 pch.hApp.xaml.cpp 源代码文件。 有关要使用的代码的示例,请参阅 AppLifecycle 示例。 请务必根据你的特定项目在 winrt::CppWinUiDesktopInstancing::implementation::App 中更改命名空间)。

要解决 [错误 C2872: "Microsoft": 符号不明确],请将 using namespace Microsoft::UI::Xaml; 更改为 using namespace winrt::Microsoft::UI::Xaml;。 对 using 指令进行任何其他类似更改。

Application.OnLaunched 中的单实例化

使用 Main 或 wWinMain 的替代方法是在 App 类的 Application.OnLaunched 方法中执行单实例化逻辑

重要

在 Application.OnLaunched 中完成此工作可以简化应用。 不过,这在很大程度上取决于应用所执行的其他操作。 如果打算结束重定向,然后终止当前实例,则需要避免执行任何一次性工作(甚至是需要显式撤消的工作)。 在这类情况下,Application.OnLaunched 可能太晚,你可能更希望在应用的 Main 或 wWinMain 函数中完成此工作

// 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();
}

或者,你可以调用 AppInstance.GetInstances 来检索正在运行的 AppInstance 对象的集合。 如果该集合中的元素数大于 1,则主实例已在运行,应重定向到该实例。

文件类型关联

在 Windows 应用 SDK 项目中,若要为文件类型关联指定扩展点,可以在 Package.appxmanifest 文件中进行相同的设置,如同对 UWP 项目进行设置一样。 下面是这些设置。

打开 Package.appxmanifest。 在“声明”中,选择“文件类型关联”,然后单击“添加”。 设置以下属性。

显示名称:MyFile 名称:myfile 文件类型:.myf

若要注册文件类型关联,请生成应用,进行启动,然后关闭。

不同之处在于强制性代码。 在 UWP 应用中,会实现 App::OnFileActivated 以便处理文件激活。 但在 Windows 应用 SDK 应用中,会在 App::OnLaunched 中编写代码,以检查已激活事件参数 (AppInstance.GetActivatedEventArgs) 的扩展激活种类 (ExtendedActivationKind),并查看激活是否为文件激活。

注意

请勿使用传递给 App::OnLaunchedMicrosoft.UI.Xaml.LaunchActivatedEventArgs 对象来确定激活类型,因为它会无条件报告“Launch”。

如果应用具有导航,则你在 App::OnLaunched 中已有导航代码,你可能要重复使用该逻辑。 有关详细信息,请参阅是否需要实现页面导航?

// 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 和其他激活处理方法

在 UWP 应用中,若要替代可以用于激活应用的各种方式,可以替代 App 类中的对应方法,例如 OnFileActivated、OnSearchActivated 或更普遍的 OnActivated

在 Windows 应用 SDK 应用中,可以在 App.OnLaunched 中(或事实上随时)调用 (AppInstance.GetActivatedEventArgs) 来检索已激活事件参数,并检查它们以确定应用的激活方式。

有关更多详细信息和代码示例,请参阅上面的文件类型关联部分。 可以对通过 ExtendedActivationKind 枚举指定的任何激活类型应用相同技术。