Использование API хостинга XAML UWP

Это важно

В этом разделе используются или упоминаются типы из репозитория CommunityToolkit/Microsoft.Toolkit.Win32 GitHub. Сведения о поддержке островов XAML UWP см. в уведомлении XAML Islands в этом репозитории.

Классические настольные приложения, отличные от UWP (включая десктопные приложения C++ (Win32), WPF и Windows Forms приложения) могут использовать API размещения UWP XAML для размещения элементов управления XAML UWP в любом элементе пользовательского интерфейса, связанном с дескриптором окна (HWND). Обзор этой функции см. в разделе "Хостинг элементов UWP XAML в приложениях для рабочего стола (UWP XAML Islands)".

Подходит ли API размещения UWP XAML для вашего настольного приложения?

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

  • Если у вас есть классическое приложение C++ и вы хотите разместить элементы управления XAML UWP в приложении, необходимо использовать API размещения XAML UWP. Для этих типов приложений нет альтернативных вариантов.

  • Для приложений WPF и Windows Forms настоятельно рекомендуется использовать элементы управления XAML Island .NET в наборе средств сообщества Windows вместо использования API размещения XAML UWP напрямую. Эти элементы управления используют API размещения XAML UWP внутри системы и реализуют все поведение, которое вам в противном случае потребуется обрабатывать, если вы использовали API размещения XAML UWP напрямую, включая навигацию по клавиатуре и изменения макета.

Поскольку мы рекомендуем использовать только настольные приложения C++ с помощью API размещения XAML UWP, эта статья в основном содержит инструкции и примеры для настольных приложений C++. Однако при выборе можно использовать API размещения XAML UWP в WPF и Windows Forms приложениях. В этой статье описывается соответствующий исходный код элементов управления host для WPF и Windows Forms в наборе средств сообщества Windows, чтобы увидеть, как API размещения XAML UWP используется этими элементами управления.

Узнайте, как использовать API размещения XAML

Чтобы следовать пошаговым инструкциям с примерами кода для использования API хостинга XAML в классических приложениях C++, ознакомьтесь со следующими статьями:

Образцы

Способ использования API размещения XAML UWP в коде зависит от типа приложения, дизайна приложения и других факторов. Чтобы иллюстрировать использование этого API в контексте полного приложения, эта статья содержит сведения о коде из следующих примеров.

Настольное приложение C++ (Win32)

В следующих примерах показано, как использовать API размещения XAML UWP в классическом приложении C++:

  • Простой пример Simple XAML Island. В этом примере показана базовая реализация интеграции элемента управления UWP XAML в настольном приложении C++ без упаковки.

  • XAML Island с примером пользовательского элемента управления. В этом примере демонстрируется полная реализация размещения пользовательского элемента управления XAML UWP в упакованом классическом приложении C++, а также обработка других действий, таких как ввод клавиатуры и навигация фокуса.

WPF и Windows Forms

Элемент управления WindowsXamlHost в наборе средств сообщества Windows служит эталонным примером использования API размещения XAML UWP в WPF и Windows Forms приложениях. Исходный код доступен в следующих расположениях:

Замечание

Настоятельно рекомендуется использовать элементы управления XAML Island .NET в наборе средств сообщества Windows вместо использования API размещения XAML UWP непосредственно в WPF и Windows Forms приложениях. Примеры ссылок WPF и Windows Forms в этой статье предназначены только для иллюстрационных целей.

Архитектура API

API размещения XAML UWP включает эти основные типы среда выполнения Windows и COM-интерфейсы.

Тип или интерфейс Description
WindowsXamlManager Этот класс представляет платформу XAML UWP. Этот класс предоставляет один статический метод InitializeForCurrentThread , который инициализирует платформу XAML UWP в текущем потоке в классическом приложении.
DesktopWindowXamlSource Этот класс представляет экземпляр содержимого XAML UWP, которое вы размещаете в своем классическом приложении для настольных ПК. Наиболее важным элементом этого класса является свойство Content . Вы назначаете это свойство элементу Windows.UI.Xaml.UIElement, который вы хотите разместить. Этот класс также имеет другие члены для маршрутизации навигации фокуса клавиатуры в XAML Islands и из них.
IDesktopWindowXamlSourceNative Этот COM-интерфейс предоставляет метод AttachToWindow , который используется для присоединения острова XAML в приложении к родительскому элементу пользовательского интерфейса. Каждый объект DesktopWindowXamlSource реализует этот интерфейс.
IDesktopWindowXamlSourceNative2 Этот COM-интерфейс предоставляет метод PreTranslateMessage , который позволяет платформе XAML UWP правильно обрабатывать определенные сообщения Windows. Каждый объект DesktopWindowXamlSource реализует этот интерфейс.

На следующей схеме показана иерархия объектов на острове XAML, размещенном в классическом приложении.

  • На базовом уровне — это элемент пользовательского интерфейса в приложении, где требуется разместить остров XAML. Этот элемент пользовательского интерфейса должен иметь дескриптор окна (HWND). Примеры элементов пользовательского интерфейса, в которых можно разместить XAML Island, включают window для настольных приложений на C++, System.Windows.Interop.HwndHost для приложений WPF и System.Windows.Forms.Control для приложений Windows Forms.

  • На следующем уровне находится объект DesktopWindowXamlSource . Этот объект предоставляет инфраструктуру для размещения острова XAML. Код отвечает за создание этого объекта и присоединение его к родительскому элементу пользовательского интерфейса.

  • При создании DesktopWindowXamlSource этот объект автоматически создает собственное дочернее окно для размещения элемента управления XAML UWP. Это собственное дочернее окно в основном скрыто от вашего кода, но при необходимости вы можете получить доступ к его дескриптору (HWND).

  • На верхнем уровне находится элемент управления XAML UWP, который вы хотите разместить в десктопном приложении. Это может быть любой объект UWP, производный от Windows.UI.Xaml.UIElement, включая любой элемент управления XAML UWP, предоставляемый пакетом SDK Windows, а также настраиваемые элементы управления.

Архитектура DesktopWindowXamlSource

Замечание

При размещении островов XAML UWP в настольном приложении можно одновременно использовать несколько деревьев содержимого XAML, запускаемых в одном потоке. Чтобы получить доступ к корневому элементу дерева содержимого XAML на XAML Island и получить связанные сведения о контексте, в котором он размещен, используйте класс XamlRoot. API CoreWindow, ApplicationView и Window не предоставляют правильные сведения для островов XAML UWP. Дополнительные сведения см. в этом разделе.

Лучшие практики

При использовании API размещения XAML UWP выполните следующие рекомендации для каждого потока, на котором размещаются элементы управления UWP XAML:

  • Создайте выделенный объект WindowsXamlManager для потока.
  • Для каждого элемента управления XAML UWP, который требуется разместить, создайте DesktopWindowXamlSource.
  • Удалите каждый DesktopWindowXamlSource после того, как он больше не нужен.
  • Перед выходом из потока удалите выделенный объект WindowsXamlManager для потока. Обратите внимание, что удаление этого объекта WindowsXamlManager является асинхронным и требует очистки очереди сообщений Windows перед выходом из потока. См. образцы XAML Islands UWP для примеров того, как это сделать.
  • После уничтожения WindowsXamlManager для данного потока создание нового WindowsXamlManager в том же потоке не поддерживается и приведет к непредсказуемому поведению.

Устранение неполадок

Ошибка использования API размещения XAML UWP в приложении UWP

Проблема Резолюция
Приложение получает COMException со следующим сообщением: "Не удается активировать DesktopWindowXamlSource." Этот тип нельзя использовать в приложении UWP или "Не удается активировать WindowsXamlManager". Этот тип нельзя использовать в приложении UWP". Эта ошибка означает, что вы пытаетесь использовать API размещения XAML UWP (в частности, вы пытаетесь создать экземпляры типов DesktopWindowXamlSource или WindowsXamlManager ) в приложении UWP. API размещения XAML UWP предназначен для использования только в настольных приложениях, отличных от UWP, таких как WPF, Windows Forms и приложения на C++.

Ошибка при попытке использовать типы WindowsXamlManager или DesktopWindowXamlSource

Проблема Резолюция
Приложение получает исключение со следующим сообщением: "WindowsXamlManager и DesktopWindowXamlSource поддерживаются для приложений, предназначенных для Windows версии 10.0.18226.0 и более поздних версий. Проверьте манифест приложения или манифест пакета и убедитесь, что свойство MaxTestedVersion обновлено". Эта ошибка указывает на то, что ваше приложение пыталось использовать типы WindowsXamlManager или DesktopWindowXamlSource в API размещения XAML UWP, но операционная система не может определить, было ли приложение создано для работы с Windows 10 версии 1903 или более поздней. API размещения XAML UWP впервые появился в качестве предварительной версии в более ранней версии Windows 10, но она поддерживается только начиная с Windows 10 версии 1903.

Чтобы устранить эту проблему, создайте пакет MSIX для приложения и запустите его из пакета, или установите пакет NuGet Microsoft.Toolkit.Win32.UI.SDK в ваш проект.

Ошибка при присоединении к окну в другом потоке

Проблема Резолюция
Приложение получает COMException со следующим сообщением: "Не удалось выполнить метод AttachToWindow, так как указанный HWND был создан в другом потоке". Эта ошибка означает, что ваше приложение вызвало метод IDesktopWindowXamlSourceNative::AttachToWindow и передало ему HWND окна, созданного в другом потоке. Вы должны передать этому методу HWND окна, которое было создано в том же потоке, что и код, из которого вы вызываете метод.

Ошибка при присоединении к окну в другом окне верхнего уровня

Проблема Резолюция
Приложение получает comException со следующим сообщением: "Метод AttachToWindow завершился сбоем, так как указанный HWND убывает от другого окна верхнего уровня, чем HWND, который ранее был передан в AttachToWindow в том же потоке". Эта ошибка означает, что ваше приложение вызвало метод IDesktopWindowXamlSourceNative::AttachToWindow и передало ему HWND окна, которое происходит от другого окна верхнего уровня, отличного от окна, указанного в предыдущем вызове этого метода в том же потоке.

После вызова приложения AttachToWindow в определенном потоке все остальные объекты DesktopWindowXamlSource на одном потоке могут подключаться только к окнам, которые являются потомками одного окна верхнего уровня, переданного в первом вызове AttachToWindow. Когда все объекты DesktopWindowXamlSource закрываются для определенного потока, следующий DesktopWindowXamlSource затем может снова присоединиться к любому окну.

Чтобы устранить эту проблему, закройте все объекты DesktopWindowXamlSource , привязанные к другим окнам верхнего уровня в этом потоке, или создайте новый поток для этого DesktopWindowXamlSource.