Уведомления приложений при переходе с UWP на WinUI 3

Единственное различие при переносе кода уведомлений приложения из UWP в WinUI заключается в обработке активации уведомлений. Отправка уведомлений приложений и управление ими остается точно такой же.

Note

Термин "всплывающее уведомление" заменяется на "уведомление приложения". Эти термины относятся к одной и той же функции Windows, но со временем мы будем постепенно отказываться от использования термина "всплывающее уведомление" в документации.

Note

Некоторые сведения относятся к предварительной версии продукта, в которую перед коммерческим выпуском могут быть внесены существенные изменения. Майкрософт не дает никаких гарантий, явных или подразумеваемых в отношении информации, предоставленной здесь.

Различия в активации

Category UWP WinUI
Точка входа активации основного режима OnActivatedВызывается метод внутри App.xaml.cs OnLaunched Вызывается метод внутри App.xaml.cs .
Точка входа в фоновую активацию Обработка отдельно в качестве фоновой задачи То же, что и активация переднего плана. OnLaunched Вызывается метод внутри App.xaml.cs . Используйте GetActivatedEventArgs, чтобы определить, должно ли приложение полностью запуститься или просто обработать задачу и завершить работу.
Активация окна Окно автоматически доведено до переднего плана при активации переднего плана При желании необходимо перенести окно на передний план

Миграция для приложений C#

Шаг 1. Установка библиотеки NuGet

Для приложения WinUI вы обрабатываете активацию уведомлений с помощью класса AppNotificationManager . Этот класс предоставляется пакетом NuGet Майкрософт.WindowsAppSDK, который включается по умолчанию в шаблоны проектов WinUI в Visual Studio.

Шаг 2. Обновление манифеста

В package.appxmanifest добавьте:

  1. Объявление для xmlns:com
  2. Объявление для xmlns:desktop
  3. В атрибуте IgnorableNamespacescom и desktop
  4. desktop:Extension для windows.toastNotificationActivation для объявления CLSID активатора toast (используя новый GUID по вашему выбору).
  5. Только MSIX: com:Extension для активатора COM с использованием GUID из шага 4. Обязательно включите Arguments="----AppNotificationActivated:", чтобы знать, что запуск был из уведомления.
<!--Add these namespaces-->
<Package
  ...
  xmlns:com="http://schemas.microsoft.com/appx/manifest/com/windows10"
  xmlns:desktop="http://schemas.microsoft.com/appx/manifest/desktop/windows10"
  IgnorableNamespaces="... com desktop">
  ...
  <Applications>
    <Application>
      ...
      <Extensions>

        <!--Specify which CLSID to activate when app notification clicked-->
        <desktop:Extension Category="windows.toastNotificationActivation">
          <desktop:ToastNotificationActivation ToastActivatorCLSID="replaced-with-your-guid-C173E6ADF0C3" /> 
        </desktop:Extension>

        <!--Register COM CLSID LocalServer32 registry key-->
        <com:Extension Category="windows.comServer">
          <com:ComServer>
            <com:ExeServer Executable="YourProject.exe" Arguments="----AppNotificationActivated:" DisplayName="App notification activator">
              <com:Class Id="replaced-with-your-guid-C173E6ADF0C3" DisplayName="App notification activator"/>
            </com:ExeServer>
          </com:ComServer>
        </com:Extension>

      </Extensions>
    </Application>
  </Applications>
 </Package>

Шаг 3. Обработка активации

В коде запуска приложения (обычно App.xaml.cs), обновите код , выполнив следующие действия:

  1. В OnLaunched получите экземпляр класса AppNotificationManager по умолчанию.
  2. Зарегистрируйте событие AppNotificationManager.NotificationInvoked.
  3. Вызовите Майкрософт.Windows.AppNotifications.AppNotificationManager.Register, чтобы зарегистрировать ваше приложение для получения событий уведомлений. Важно, чтобы этот метод вызывался после регистрации обработчика NotificationInvoked .
  4. Перефакторизуйте ваш код запуска/активации окна в специально выделенную LaunchAndBringToForegroundIfNeeded вспомогательную функцию, чтобы можно было вызывать её из нескольких мест.
  5. Создайте вспомогательный HandleNotification метод, чтобы его можно было вызывать из нескольких мест.
  6. Вызовите AppInstance.GetActivatedEventArgs и проверьте свойство AppActivationArguments.Kind возвращаемого объекта для значения ExtendedActivationKind.AppNotification.
  7. Если тип активации не равен AppNotification, вызовите вспомогательный метод LaunchAndBringToForegroundIfNeeded.
  8. Если тип активации — AppNotification, преобразуйте свойство AppActivationArguments.Data в объект AppNotificationActivatedEventArgs и передайте его вспомогательному HandleNotification методу.
  9. В обработчике ApplicationManager.NotificationInvoked вызовите вспомогательный HandleNotification метод.
  10. В методе помощника HandleNotification перед выполнением любого кода, связанного с пользовательским интерфейсом, такого как отображение окна или обновление интерфейса, обязательно выполните диспетчеризацию в диспетчер приложения или окна.
  11. Перенос старого кода UWP OnActivated , обрабатывающего активацию уведомлений приложения, в новый HandleNotification вспомогательный метод.

Файл App.xaml.cs после миграции


protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args)
{
    m_window = new MainWindow();

    // To ensure all Notification handling happens in this process instance, register for
    // NotificationInvoked before calling Register(). Without this a new process will
    // be launched to handle the notification.
    AppNotificationManager notificationManager = AppNotificationManager.Default;
    notificationManager.NotificationInvoked += NotificationManager_NotificationInvoked;
    notificationManager.Register();

    var activatedArgs = Microsoft.Windows.AppLifecycle.AppInstance.GetCurrent().GetActivatedEventArgs();
    var activationKind = activatedArgs.Kind;
    if (activationKind != ExtendedActivationKind.AppNotification)
    {
        LaunchAndBringToForegroundIfNeeded();
    } else
    {
        HandleNotification((AppNotificationActivatedEventArgs)activatedArgs.Data);
    }

}

private void LaunchAndBringToForegroundIfNeeded()
{
    if (m_window == null)
    {
        m_window = new MainWindow();
        m_window.Activate();

        // Additionally we show using our helper, since if activated via a app notification, it doesn't
        // activate the window correctly.
        WindowHelper.ShowWindow(m_window);
    }
    else
    {
        WindowHelper.ShowWindow(m_window);
    }
}

private void NotificationManager_NotificationInvoked(AppNotificationManager sender, AppNotificationActivatedEventArgs args)
{
    HandleNotification(args);
}

private void HandleNotification(AppNotificationActivatedEventArgs args)
{
  // Use the dispatcher from the window if present, otherwise the app dispatcher.
  var dispatcherQueue = m_window?.DispatcherQueue ?? DispatcherQueue.GetForCurrentThread();


  dispatcherQueue.TryEnqueue(async delegate
  {
      if (args.Argument.Contains("action"))
      {
          switch (args.Arguments["action"])
          {
              // Send a background message.
              case "sendMessage":
                  string message = args.UserInput["textBox"].ToString();
                  // TODO: Send it.
    
                  // If the UI app isn't open.
                  if (m_window == null)
                  {
                      // Close since we're done.
                      Process.GetCurrentProcess().Kill();
                  }
    
                  break;
    
              // View a message.
              case "viewMessage":
    
                  // Launch/bring window to foreground.
                  LaunchAndBringToForegroundIfNeeded();
    
                  // TODO: Open the message.
                  break;
          }
      }
      else
      {
          Debug.Print("Notification args is null");
      }
  });
}

private static class WindowHelper
{
    [DllImport("user32.dll")]
    private static extern bool ShowWindow(IntPtr hWnd, int nCmdShow);

    [DllImport("user32.dll")]
    [return: MarshalAs(UnmanagedType.Bool)]
    private static extern bool SetForegroundWindow(IntPtr hWnd);

    public static void ShowWindow(Window window)
    {
        // Bring the window to the foreground... first get the window handle...
        var hwnd = WinRT.Interop.WindowNative.GetWindowHandle(window);

        // Restore window if minimized... requires DLL import above
        ShowWindow(hwnd, 0x00000009);

        // And call SetForegroundWindow... requires DLL import above
        SetForegroundWindow(hwnd);
    }
}

Создание содержимого уведомления о приложении

С помощью Windows App SDK вы по-прежнему можете создавать содержимое уведомлений приложений с помощью необработанного XML-кода, но вы также можете создавать содержимое уведомлений приложения с помощью нового AppNotificationsBuilder API, который заменяет api ToastContentBuilder предоставляемый набором средств сообщества Windows. Отправьте уведомление о приложении, вызвав AppNotificationManager.Show. Не рекомендуется смешивать Windows Community Toolkit и API App SDK.

using Microsoft.Windows.AppNotifications;
using Microsoft.Windows.AppNotifications.Builder;

...

var builder = new AppNotificationBuilder()
    .AddText("Send a message.")
    .AddTextBox("textBox")
    .AddButton(new AppNotificationButton("Send")
        .AddArgument("action", "sendMessage"));

var notificationManager = AppNotificationManager.Default;
notificationManager.Show(builder.BuildNotification());