应用程序生命周期功能迁移
本主题包含应用程序生命周期区域中的迁移指南。
重要的 API
- AppInstance 类
- Application.OnLaunched 方法
- AppInstance.GetActivatedEventArgs 方法
- ExtendedActivationKind 枚举
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.FindOrRegisterForKey 和 AppInstance.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.h
和 App.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::OnLaunched 的 Microsoft.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 枚举指定的任何激活类型应用相同技术。