Использование API размещения WinRT XAML в классическом приложении C++ (Win32)
Внимание
В этом разделе используются или упоминаются типы из репозитория CommunityToolkit/Microsoft.Toolkit.Win32 GitHub. Дополнительные сведения о поддержке XAML Islands см . в уведомлении о xaml Islands в этом репозитории.
Начиная с Windows 10 версии 1903, не относящиеся к платформе UWP классические приложения (включая приложения C++ (Win32), WPF и Windows Forms) могут использовать API размещения WinRT XAML для размещения элементов управления WinRT XAML в любом элементе пользовательского интерфейса, связанном с дескриптором окна (HWND). Этот API позволяет классическим приложениям, не относящимся к UWP, использовать новейшие возможности пользовательского интерфейса Windows, которые доступны только через элементы управления WinRT XAML. Например, классические приложения, не относящиеся к UWP, могут использовать этот API для размещения элементов управления WinRT XAML, которые используют систему Fluent Design и поддерживают Windows Ink.
API размещения WinRT XAML создает основу с более широким набором элементов управления, который мы предоставляем разработчикам для реализации пользовательского интерфейса Fluent в классических приложениях, не относящихся к UWP. Эта возможность называется XAML Islands. Общие сведения об этой возможности см. в статье Размещение элементов управления WinRT XAML в классических приложениях (XAML Islands).
Примечание.
Если вы хотите поделиться мнением об XAML Island, создайте запрос в репозитории Microsoft.Toolkit.Win32 и оставьте свои комментарии.
Является ли API размещения WinRT XAML правильным выбором для классического приложения?
Этот API предоставляет низкоуровневую инфраструктуру для размещения элементов управления WinRT XAML в классических приложениях. Для классических приложений некоторых типов можно использовать альтернативные более удобные API-интерфейсы для выполнения этой задачи.
Если у вас есть классическое приложение C++ и вы хотите разместить элементы управления WinRT XAML в приложении, необходимо использовать API размещения WinRT XAML. Для таких типов приложений нет альтернативы.
Для приложений WPF и Windows Forms мы настоятельно рекомендуем применять элементы управления XAML Islands .NET из набора средств сообщества Windows, а не использовать API размещения WinRT XAML. Эти элементы управления используют API размещения WinRT XAML на внутреннем уровне и реализуют все типы поведения, которые при использовании этого API напрямую пришлось бы реализовать самостоятельно, в том числе навигацию с помощью клавиатуры и изменение раскладки.
Так как мы рекомендуем, чтобы только классические приложения C++ использовали API размещения WinRT XAML, в этой статье приводятся инструкции и примеры преимущественно для классических приложений C++. Но API размещения WinRT XAML можно использовать в приложениях WPF и Windows Forms при необходимости. В этой статье рассматривается соответствующий исходный код для элементов управления ведущего приложения для WPF и Windows Forms в наборе средств сообщества Windows, чтобы вы могли увидеть, как API размещения WinRT XAML используется этими элементами управления.
Как использовать API размещения XAML
Чтобы выполнить пошаговые инструкции с примерами кода по использованию API размещения XAML в классических приложениях C++, см. следующие статьи:
- Размещение стандартного элемента управления WinRT XAML
- Размещение пользовательского элемента управления WinRT XAML
- Расширенные сценарии XAML Islands в приложениях Win32 на C++
Примеры
Способ использования API размещения WinRT XAML в коде зависит от типа, структуры приложения и других факторов. Чтобы продемонстрировать, как использовать этот API в контексте целого приложения, в этой статье рассматриваются следующие примеры кода.
Классические приложения C++ (Win32)
В следующих примерах показано, как использовать API размещения WinRT XAML в классическом приложении C++:
Простой пример XAML Islands. В этом примере показана базовая реализация размещения элемента управления WinRT XAML в классическом приложении C++ для распаковки.
Пример XAML Islands с настраиваемым элементом управления. Здесь показана полная реализация размещения пользовательского элемента управления WinRT XAML в упакованном классическом приложении C++, а также обработка других типов поведения, таких как ввод с клавиатуры и перемещение фокуса.
WPF и Windows Forms
Элемент управления WindowsXamlHost в наборе средств сообщества Windows служит эталонным примером использования API размещения WinRT XAML в приложениях WPF и Windows Forms. Исходный код доступен по ссылкам ниже.
Для версии WPF перейдите сюда. Версия WPF является производной от System.Windows.Interop.HwndHost.
Для версии Windows Forms перейдите сюда. Версия Windows Forms является производной от System.Windows.Forms.Control.
Примечание.
Мы настоятельно рекомендуем применять элементы управления XAML Islands .NET из набора средств сообщества Windows, а не использовать API размещения WinRT XAML напрямую в приложениях WPF и Windows Forms. В этой статье ссылки на примеры WPF и Windows Forms приведены только для наглядности.
Архитектура API
API размещения WinRT XAML предусматривает следующие основные типы среды выполнения Windows и COM-интерфейсы.
Тип или интерфейс | Description |
---|---|
WindowsXamlManager | Этот класс представляет платформу XAML для элементов UWP. Он предоставляет один статический метод InitializeForCurrentThread, который инициализирует платформу XAML для UWP в текущем потоке классического приложения. |
DesktopWindowXamlSource | Этот класс представляет экземпляр содержимого UWP XAML, которое размещается в классическом приложении. Самым важным членом этого класса является свойство Content. Вы назначаете это свойство элементу Windows.UI.Xaml.UIElement, который требуется разместить. Этот класс также содержит другие члены для маршрутизации фокуса с клавиатуры на объекты XAML Islands и с них. |
IDesktopWindowXamlSourceNative | Этот COM-интерфейс предоставляет метод AttachToWindow, который используется для присоединения элемента XAML Islands к родительскому элементу пользовательского интерфейса в приложении. Каждый объект DesktopWindowXamlSource реализует этот интерфейс. |
IDesktopWindowXamlSourceNative2 | Этот COM-интерфейс предоставляет метод PreTranslateMessage, который позволяет платформе XAML для UWP правильно обрабатывать определенные сообщения Windows. Каждый объект DesktopWindowXamlSource реализует этот интерфейс. |
На следующей схеме показана иерархия объектов в элементе XAML Islands в классическом приложении.
На базовом уровне находится элемент пользовательского интерфейса в приложении, в котором требуется разместить элемент XAML Islands. У этого элемента пользовательского интерфейса должен быть HWND. Примеры элементов пользовательского интерфейса, в которых можно разместить XAML Islands, включают Window для классических приложений C++, System.Windows.Interop.HwndHost для приложений WPF и System.Windows.Forms.Control для приложений Windows Forms.
На следующем уровне находится объект DesktopWindowXamlSource. Этот объект предоставляет инфраструктуру для размещения элемента XAML Islands. Ваш код отвечает за создание этого объекта и его присоединение к родительскому элементу пользовательского интерфейса.
При создании DesktopWindowXamlSource этот объект автоматически создает собственное дочернее окно для размещения элемента управления WinRT XAML. Это собственное дочернее окно в основном абстрагировано от кода, но при необходимости можно получить доступ к его HWND.
Наконец, на верхнем уровне находится элемент управления WinRT XAML, который требуется разместить в классическом приложении. Это может быть любой объект UWP, производный от Windows.UI.Xaml.UIElement, в том числе любой элемент управления WinRT XAML, предоставляемый в пакете Windows SDK, а также пользовательский элемент управления.
Примечание.
При размещении объектов XAML Island в классическом приложении можно одновременно использовать несколько деревьев содержимого XAML, выполняющихся в одном и том же потоке. Для доступа к корневому элементу дерева содержимого XAML в XAML Island и получения связанных сведений о контексте, в котором он размещен, используйте класс XamlRoot. API-интерфейсы CoreWindow, ApplicationView и Window не предоставляют правильную информацию об объектах XAML Islands. Дополнительные сведения см. в этом разделе.
Рекомендации
При использовании API размещения XAML WinRT следуйте приведенным ниже рекомендациям для каждого потока, в котором размещены элементы управления XAML WinRT:
- Создайте выделенный экземпляр WindowsXamlManager для потока.
- Для каждого элемента управления XAML WinRT, который требуется разместить, создайте экземпляр DesktopWindowXamlSource.
- Уничтожьте каждый ставший ненужным экземпляр DesktopWindowXamlSource.
- Перед выходом из потока уничтожьте выделенный экземпляр WindowsXamlManager для потока. Обратите внимание, что уничтожение этого экземпляра WindowsXamlManager является асинхронным и требует очистки очереди сообщений Windows перед выходом из потока. Примеры того, как это сделать, см. на странице с примерами кода XAML Islands.
- После уничтожения экземпляра WindowsXamlManager для указанного потока создание нового экземпляра WindowsXamlManager в том же потоке не поддерживается и приведет к непредсказуемому поведению.
Устранение неполадок
Ошибка использования API размещения WinRT XAML в приложении UWP
Проблема | Решение |
---|---|
Приложение получает COMException со следующим сообщением: Cannot activate DesktopWindowXamlSource. Этот тип не может использоваться в приложении UWP" или "Не удалось активировать WindowsXamlManager. This type cannot be used in a UWP app." (Не удалось активировать DesktopWindowXamlSource. Этот тип нельзя использовать в приложении UWP.) | Эта ошибка означает, что вы пытаетесь использовать API размещения WinRT XAML (в частности, вы пытаетесь создать экземпляры типов DesktopWindowXamlSource или WindowsXamlManager) в приложении UWP. API размещения WinRT XAML предназначен для использования только в классических приложениях, не относящихся к UWP, включая приложения WPF, Windows Forms и C++. |
Ошибка при попытке использовать типы WindowsXamlManager или DesktopWindowXamlSource
Проблема | Решение |
---|---|
Приложение получает исключение со следующим сообщением: "WindowsXamlManager и DesktopWindowXamlSource поддерживаются для приложений, предназначенных для Windows версии 10.0.18226.0 и более поздних". Please check either the application manifest or package manifest and ensure the MaxTestedVersion property is updated." (WindowsXamlManager и DesktopWindowXamlSource поддерживаются для приложений, предназначенных для Windows версии 10.0.18226.0 и более поздних. Проверьте манифест приложения или манифест пакета и убедитесь, что свойство MaxTestedVersion обновлено.) | Эта ошибка означает, что приложение пыталось использовать типы WindowsXamlManager или DesktopWindowXamlSource в API размещения WinRT XAML, но ОС не может определить, создано ли приложение для Windows 10 версии 1903 или более поздних. API размещения WinRT XAML впервые появился в виде ознакомительной версии в более ранней версии Windows 10, но поддерживается только начиная с Windows 10 версии 1903.Чтобы устранить эту проблему, создайте пакет MSIX для приложения и запустите его из пакета или установите пакет NuGet Microsoft.Toolkit.Win32.UI.SDK в проекте. |
Ошибка присоединения к окну в другом потоке
Проблема | Решение |
---|---|
Приложение получает COMException со следующим сообщением: AttachToWindow method failed because the specified HWND was created on a different thread. (Сбой метода AttachToWindow, так как указанный HWND создан в другом потоке.) | Эта ошибка означает, что приложение вызвало метод IDesktopWindowXamlSourceNative::AttachToWindow и передало ему HWND окна, созданный в другом потоке. Этот метод необходимо передать в HWND окна, созданный в том же потоке, что и код, из которого вызывается метод. |
Ошибка присоединения к окну в другом окне верхнего уровня
Проблема | Решение |
---|---|
Приложение получает исключение COMException со следующим сообщением: "Сбой метода AttachToWindow, так как указанный HWND, производный от другого окна верхнего уровня, отличается от HWND, который ранее передан в AttachToWindow в том же потоке". | Эта ошибка означает, что приложение вызвало метод IDesktopWindowXamlSourceNative::AttachToWindow и передало ему HWND окна, производный от другого окна верхнего уровня, отличного от указанного окна в предыдущем вызове этого метода в этом же потоке.После того как приложение вызовет AttachToWindow в определенном потоке, все остальные объекты DesktopWindowXamlSource в том же потоке могут быть присоединены только к окнам, являющимся потомками того же окна верхнего уровня, которое передано в первый вызов AttachToWindow. Когда все объекты DesktopWindowXamlSource закрыты для конкретного потока, следующий DesktopWindowXamlSource снова можно присоединить к любому окну.Чтобы устранить эту проблему, закройте все объекты DesktopWindowXamlSource, привязанные к другим окнам верхнего уровня в этом потоке, или создайте другой поток для этого DesktopWindowXamlSource. |
См. также
- Элементы управления UWP XAML в классических приложениях (XAML Islands)
- Размещение стандартного элемента управления WinRT XAML в классическом приложении C++
- Размещение настраиваемого элемента управления WinRT XAML в классическом приложении C++
- Расширенные сценарии использования XAML Islands в классических приложениях C++
- Примеры кода для XAML Islands
- Пример XAML Islands для классического приложения C++
Windows developer