Поделиться через


Расширенные сценарии использования XAML Islands в классических приложениях С++ (Win32)

Важно!

В этом разделе используются или упоминание типы из сообщества набор средств/Microsoft.набор средств. Репозиторий Win32 GitHub. Дополнительные сведения о поддержке XAML Islands см . в уведомлении о xaml Islands в этом репозитории.

В статьях о размещении стандартного и настраиваемого элементов управления UWP представлены инструкции и примеры по размещению XAML Islands в классических приложениях C++ (Win32). Но примеры кода в этих статьях не подходят для многих расширенных сценариев, которые могут обеспечить эффективное взаимодействие с пользователем в классических приложениях. Эта статья содержит рекомендации по некоторым из таких сценариев и ссылки на соответствующие примеры кода.

Ввод с клавиатуры

Чтобы правильно обрабатывать ввод с клавиатуры для каждого XAML Island, приложение должно передавать все сообщения Windows платформе UWP XAML, чтобы она правильно обрабатывала нужные сообщения. Для этого создайте для каждого XAML Island объект DesktopWindowXamlSource, привязанный к интерфейсу COM IDesktopWindowXamlSourceNative2 в любом месте приложения, из которого есть доступ к циклу сообщений. Затем вызовите метод PreTranslateMessage из этого интерфейса и передайте ему текущее сообщение.

  • C++ (Win32): приложение может вызывать PreTranslateMessage прямо из главного цикла обработки сообщений. Пример можно найти в файле XamlBridge.cpp.

  • WPF: приложение может вызывать PreTranslateMessage из обработчика событий для события ComponentDispatcher.ThreadFilterMessage. Пример представлен в файле WindowsXamlHostBase.Focus.cs из набора средств сообщества Windows.

  • Windows Forms: приложение может вызывать PreTranslateMessage из переопределения для метода Control.PreprocessMessage. Пример представлен в файле WindowsXamlHostBase.KeyboardFocus.cs из набора средств сообщества Windows.

Перемещение фокуса с клавиатуры

Когда пользователь перемещается между элементами пользовательского интерфейса в приложении с помощью клавиатуры (например, нажимая клавишу Tab или клавиши со стрелками), вам нужно программным образом включать и отключать фокус ввода в объекте DesktopWindowXamlSource. Когда пользователь достигнет объекта DesktopWindowXamlSource, передайте фокус первому из объектов Windows.UI.Xaml.UIElement в соответствии с порядком навигации в вашем пользовательском интерфейсе, затем поочередно перебирайте объекты Windows.UI.Xaml.UIElement при перемещениях пользователя, и наконец уберите фокус из DesktopWindowXamlSource в его родительский элемент пользовательского интерфейса.

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

  • Когда навигация с помощью клавиатуры достигает объекта DesktopWindowXamlSource, создается событие GotFocus. Обрабатывайте это сообщение, программным образом перемещая фокус на первый из размещенных объектов Windows.UI.Xaml.UIElement с помощью метода NavigateFocus.

  • Когда пользователь достигает последнего из элементов, поддерживающих получение фокуса, в DesktopWindowXamlSource и нажимает клавишу Tab или клавишу со стрелкой, создается событие TakeFocusRequested. Обрабатывайте это сообщение, программным образом перемещая фокус на следующий элемент в базовом приложении, поддерживающий фокус. Например, если в приложении WPF элемент DesktopWindowXamlSource размещается в System.Windows.Interop.HwndHost, вы можете с помощью метода MoveFocus переместить фокус на следующий элемент в базовом приложении, поддерживающий фокус.

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

Обработка изменений макета

Когда пользователь изменяет размер родительского элемента пользовательского интерфейса, вам следует обработать все необходимые изменения макета, чтобы элементы управления UWP отображались правильно. Вот несколько важных факторов, которые нужно учитывать.

  • В классическом приложении C++ (Win32) при обработке сообщения WM_SIZE можно переместить размещенный элемент XAML Islands с помощью функции SetWindowPos. Пример можно изучить в файле кода SampleApp.cpp.

  • Когда родительскому элементу пользовательского интерфейса потребуется получить размер прямоугольной области для размещения Windows.UI.Xaml.UIElement, который находится в вашем DesktopWindowXamlSource, вызовите метод Measure из Windows.UI.Xaml.UIElement. Например:

    • В приложении WPF это можно выполнять из метода MeasureOverride в HwndHost, где размещается этот DesktopWindowXamlSource. Пример представлен в файле WindowsXamlHostBase.Layout.cs из набора средств сообщества Windows.

    • В приложении Windows Forms это можно выполнять из метода GetPreferredSize в Control, где размещается этот DesktopWindowXamlSource. Пример представлен в файле WindowsXamlHostBase.Layout.cs из набора средств сообщества Windows.

  • Когда изменится размер родительского элемента пользовательского интерфейса, вызовите метод Arrange из корневого элемента Windows.UI.Xaml.UIElement, который вы размещаете в DesktopWindowXamlSource. Например:

    • В приложении WPF это можно выполнять из метода ArrangeOverride объекта HwndHost, где размещается этот DesktopWindowXamlSource. Пример представлен в файле WindowsXamlHost.Layout.cs из набора средств сообщества Windows.

    • В приложении Windows Forms это можно выполнять из обработчика события SizeChanged в Control, где размещается этот DesktopWindowXamlSource. Пример представлен в файле WindowsXamlHost.Layout.cs из набора средств сообщества Windows.

Обработка изменений количества точек на дюйм

Платформа UWP XAML автоматически обрабатывает изменения количества точек на дюйм для размещенных элементов управления UWP (например, при перетаскивании окна между мониторами с разными значениями количества точек на дюйм). Чтобы оптимизировать взаимодействие с пользователем, мы рекомендуем в классических приложениях Windows Forms, WPF и C++ учитывать количество точек на дюйм для каждого монитора.

Чтобы настроить в приложении учет количества точек на дюйм для каждого монитора, добавьте манифест сборки для параллельного отображения в проект и присвойте элементу <dpiAwareness> значение PerMonitorV2. Дополнительные сведения об этом значении см. в статье с описанием DPI_AWARENESS_CONTEXT_PER_MONITOR_AWARE_V2.

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
    <application xmlns="urn:schemas-microsoft-com:asm.v3">
        <windowsSettings>
            <dpiAwareness xmlns="http://schemas.microsoft.com/SMI/2016/WindowsSettings">PerMonitorV2</dpiAwareness>
        </windowsSettings>
    </application>
</assembly>