Перенос функций управления жизненным циклом приложения

В этом разделе содержатся рекомендации по миграции в области жизненного цикла приложения.

Важные API

Сводка различий между API и (или) функциями

Приложения Universal Windows Platform (UWP) по умолчанию являются одноэкземплярными; приложения Windows App SDK (WinUI 3) по умолчанию являются многоэкземплярными.

Приложение UWP имеет методы App, такие как OnFileActivated, OnSearchActivated, OnActivated и OnBackgroundActivated, которые неявно сообщают, как было активировано приложение; В приложении Windows App SDK в App.OnLaunched (или в любом методе), вызовите (AppInstance.GetActivatedEventArgs), чтобы получить аргументы события активации и проверить их для определения способа активации приложения.

Также см. строку фоновых задач в таблице в разделе "Что поддерживается при миграции с UWP на WinUI ".

Одноэлементные приложения

приложения Universal Windows Platform (UWP) по умолчанию являются однократно запускаемыми (вы можете выбрать поддержку нескольких экземпляров — см. раздел Создание приложения UWP с поддержкой нескольких экземпляров).

При запуске одноэкземплярного приложения UWP, когда вы открываете его второй (и последующий) раз, активируется текущий экземпляр. Предположим, что в приложении UWP вы реализовали функцию сопоставления типов файлов. Если из проводника вы открываете файл (типа, для которого приложение зарегистрировало сопоставление типов файлов), и приложение уже запущено, то этот уже запущенный экземпляр активируется.

Приложения Windows App SDK (WinUI), с другой стороны, по умолчанию поддерживают несколько экземпляров. Следовательно, по умолчанию при втором (и последующем) запуске приложения Windows App SDK (WinUI) открывается новый экземпляр приложения. Если, например, приложение Windows App SDK (WinUI) реализует сопоставление типов файлов, и вы открываете файл (правильного типа) из Проводника, когда приложение уже запущено, то по умолчанию запускается новый экземпляр приложения.

Если вы хотите, чтобы ваше приложение Windows App SDK (WinUI) было одноэкземплярным, как и ваше приложение UWP, то можно переопределить поведение по умолчанию, описанное выше. Вы будете использовать AppInstance.FindOrRegisterForKey и AppInstance.IsCurrent , чтобы определить, является ли текущий экземпляр основным экземпляром. Если это не так, то вызовите AppInstance.RedirectActivationToAsync для перенаправления активации в уже запущенный основной экземпляр, а затем выйти из текущего экземпляра (без создания и активации его главного окна).

Дополнительные сведения см. в разделе «Инстанцирование приложений с использованием API жизненного цикла приложения».

Внимание

Приведенный ниже код работает должным образом, если вы нацелены на архитектуру x64 . Это относится как к C#, так и к C++/WinRT.

Одиночное инстанцирование в Main или wWinMain

Лучше всего проверить, требуется ли перенаправление активации, как можно раньше в процессе выполнения приложения. По этой причине рекомендуется выполнить логику одноинстантирования в функции Main приложения (или wWinMain для C++/WinRT). В этом разделе показано, как это сделать.

Обычно основная функция приложения создается системой сборки и помещается в скрытый файл. Поэтому первым шагом является настройка проекта, чтобы не было автоматического создания этой функции. Чтобы сделать это, вы должны определить символ DISABLE_XAML_GENERATED_MAIN в свойствах проекта Properties.

Инструкции по C#

Перейдите к Свойства> (выберите Все конфигурации и Все платформы) >Сборка>Условные символы компиляции, и вставьте символ DISABLE_XAML_GENERATED_MAIN.

Так как мы только что не позволили project автоматически создавать функцию Main, project не будет создаваться в данный момент. Поэтому второй и последний шаг — реализовать собственную версию этой функции в файле исходного кода.

Добавьте новый элемент project типа Class в project и назовите его Program.cs. Внутри Program.cs замените код class Program {} на вашу собственную реализацию. Пример используемого кода см. в разделе Program.cs в примере AppLifecycle.

Инструкции по C++/WinRT

Перейдите к свойствам> (выберите Все конфигурации и Все платформы) >Свойства конфигурации>C/C++>Предпроцессор>Определения предпроцессора, измените значение и добавьте символ DISABLE_XAML_GENERATED_MAIN.

Так как мы только что не позволили project автоматически создавать функцию wWinMain, project не будет создаваться в данный момент. Поэтому второй и последний шаг — реализовать собственную версию этой функции в файле исходного кода.

Добавьте ссылку на пакет 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 является реализация логики одноразового экземпляра в методе Application.OnLaunched класса App.

Внимание

Выполнение этой работы в Application.OnLaunched может упростить ваше приложение. Тем не менее, многое зависит от того, что еще делает ваше приложение. Если вы собираетесь в конечном итоге перенаправить, а затем завершить текущий экземпляр, то вы захотите избежать выполнения любой бесполезной работы (или даже работы, которую нужно явно отменить). В таких случаях, когда Application.OnLaunched может оказаться слишком поздним, вы можете предпочесть выполнить работу в функции Main или wWinMain.

// App.xaml.cs in a Windows App SDK (WinUI) 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) 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 App SDK, чтобы указать точку расширения для ассоциации типов файлов, выполните те же настройки в файле Package.appxmanifest, что и для проекта UWP. Ниже приведены эти параметры.

Открыть Package.appxmanifest. В объявлениях выберите сопоставления типов файлов и нажмите кнопку "Добавить". Задайте следующие свойства.

Отображаемое имя: MyFile Name: myfile File type: .myf

Чтобы зарегистрировать сопоставление типов файлов, создайте приложение, запустите его и закройте его.

Разница возникает в императивном коде. В приложении UWP вы реализуете App::OnFileActivated для обработки активации файлов. Но в приложении Windows App SDK вы пишете код в App::OnLaunched, чтобы проверить тип расширенной активации (ExtendedActivationKind) аргументов активированного события (AppInstance.GetActivatedEventArgs) и определить, является ли активация активацией файла.

Примечание.

Не используйте объект Microsoft.UI.Xaml.LaunchActivatedEventArgs, переданный в App::OnLaunched, чтобы определить тип активации, так как он всегда возвращает "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 для переопределения различных средств, с помощью которых можно активировать приложение, можно переопределить соответствующие методы в классе приложения, например OnFileActivated, OnSearchActivated или более общей OnActivated.

В приложении Windows App SDK в App.OnLaunched (или фактически в любое время) можно вызвать (AppInstance.GetActivatedEventArgs), чтобы получить активируемые события args и проверить их, чтобы определить, как было активировано приложение.

Дополнительные сведения и пример кода см. в разделе сопоставления типов файлов выше. Вы можете применить тот же метод для любого типа активации, указанного в перечислении ExtendedActivationKind .