Advanced scenarios for XAML Islands in C++ desktop (Win32) apps
Important
This topic uses or mentions types from the CommunityToolkit/Microsoft.Toolkit.Win32 GitHub repo. For important info about XAML Islands support, please see the XAML Islands Notice in that repo.
The host a standard UWP control and host a custom UWP control articles provide instructions and examples for hosting XAML Islands in a C++ desktop (Win32) app. However, the code examples in these articles do not handle many advanced scenarios that desktop applications may need to handle to provide a smooth user experience. This article provides guidance for some of these scenarios and pointers to related code samples.
Keyboard input
To properly handle keyboard input for each XAML Island, your application must pass all Windows messages to the UWP XAML framework so that certain messages can be processed correctly. To do this, in some place in your application that can access the message loop, cast the DesktopWindowXamlSource object for each XAML Island to an IDesktopWindowXamlSourceNative2 COM interface. Then, call the PreTranslateMessage method of this interface and pass in the current message.
C++ desktop (Win32):: The app can call PreTranslateMessage directly in its main message loop. For an example, see the XamlBridge.cpp file.
WPF: The app can call PreTranslateMessage from the event handler for the ComponentDispatcher.ThreadFilterMessage event. For an example, see the WindowsXamlHostBase.Focus.cs file in the Windows Community Toolkit.
Windows Forms: The app can call PreTranslateMessage from an override for the Control.PreprocessMessage method. For an example, see the WindowsXamlHostBase.KeyboardFocus.cs file in the Windows Community Toolkit.
Keyboard focus navigation
When the user navigates through the UI elements in your application using the keyboard (for example, by pressing Tab or direction/arrow key), you'll need to programmatically move focus into and out of the DesktopWindowXamlSource object. When the user's keyboard navigation reaches the DesktopWindowXamlSource, move focus into the first Windows.UI.Xaml.UIElement object in the navigation order for your UI, continue to move focus to the following Windows.UI.Xaml.UIElement objects as the user cycles through the elements, and then move focus back out of the DesktopWindowXamlSource and into the parent UI element.
The UWP XAML hosting API provides several types and members to help you accomplish these tasks.
When the keyboard navigation enters your DesktopWindowXamlSource, the GotFocus event is raised. Handle this event and programmatically move focus to the first hosted Windows.UI.Xaml.UIElement by using the NavigateFocus method.
When the user is on the last focusable element in your DesktopWindowXamlSource and presses the Tab key or an arrow key, the TakeFocusRequested event is raised. Handle this event and programmatically move focus to the next focusable element in the host application. For example, in a WPF application where the DesktopWindowXamlSource is hosted in a System.Windows.Interop.HwndHost, you can use the MoveFocus method to transfer focus to the next focusable element in the host application.
For examples that demonstrate how to do this in the context of a working sample application, see the following code files:
C++ desktop (Win32): See the XamlBridge.cpp file.
WPF: See the WindowsXamlHostBase.Focus.cs file in the Windows Community Toolkit.
Windows Forms: See the WindowsXamlHostBase.KeyboardFocus.cs file in the Windows Community Toolkit.
Handle layout changes
When the user changes the size of the parent UI element, you'll need to handle any necessary layout changes to make sure your UWP controls display as you expect. Here are some important scenarios to consider.
In a C++ desktop application, when your application handles the WM_SIZE message it can reposition the hosted XAML Island by using the SetWindowPos function. For an example, see the SampleApp.cpp code file.
When the parent UI element needs to get the size of the rectangular area needed to fit the Windows.UI.Xaml.UIElement that you are hosting on the DesktopWindowXamlSource, call the Measure method of the Windows.UI.Xaml.UIElement. For example:
In a WPF application you might do this from the MeasureOverride method of the HwndHost that hosts the DesktopWindowXamlSource. For an example, see the WindowsXamlHostBase.Layout.cs file in the Windows Community Toolkit.
In a Windows Forms application you might do this from the GetPreferredSize method of the Control that hosts the DesktopWindowXamlSource. For an example, see the WindowsXamlHostBase.Layout.cs file in the Windows Community Toolkit.
When the size of the parent UI element changes, call the Arrange method of the root Windows.UI.Xaml.UIElement that you are hosting on the DesktopWindowXamlSource. For example:
In a WPF application you might do this from the ArrangeOverride method of the HwndHost object that hosts the DesktopWindowXamlSource. For an example, see the WindowsXamlHost.Layout.cs file in the Windows Community Toolkit.
In a Windows Forms application you might do this from the handler for the SizeChanged event of the Control that hosts the DesktopWindowXamlSource. For an example, see the WindowsXamlHost.Layout.cs file in the Windows Community Toolkit.
Handle DPI changes
The UWP XAML framework handles DPI changes for hosted UWP controls automatically (for example, when the user drags the window between monitors with different screen DPI). For the best experience, we recommend that your Windows Forms, WPF, or C++ desktop application is configured to be per-monitor DPI aware.
To configure your application to be per-monitor DPI aware, add a side-by-side assembly manifest to your project and set the <dpiAwareness> element to PerMonitorV2. For more information about this value, see the description for 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>