Размещение настраиваемого элемента управления WinRT XAML в классическом приложении C++ (Win32)

Важно!

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

В этой статье описано, как разместить настраиваемый элемент управления WinRT XAML в новом классическом приложении C++ с помощью API размещения WinRT XAML. Если у вас есть проект классического приложения C++, вы можете адаптировать эти шаги и примеры кода.

Чтобы разместить настраиваемый элемент управления WinRT XAML, в рамках этого пошагового руководства вы создадите следующие проекты и компоненты:

  • Проект классического приложения для Windows. Этот проект реализует собственное классическое приложение C++. Вы добавите код в этот проект, использующий API размещения WinRT XAML для размещения настраиваемого элемента управления WinRT XAML.

  • Проект приложения UWP (C++/WinRT). Этот проект реализует настраиваемый элемент управления WinRT XAML. Он также реализует корневой поставщик метаданных для загрузки метаданных настраиваемых типов WinRT XAML в проекте.

Требования

  • Visual Studio 2019 версии 16.4.3 и более поздних версий.
  • Windows 10 версии 1903 SDK (версия 10.0.18362) или более поздней версии.
  • Расширение Visual Studio (VSIX) C++/WinRT, установленное с помощью Visual Studio. C++/WinRT — это полностью стандартная проекция языка C++17 для API среды выполнения Windows (WinRT), реализованная как библиотека на основе файлов заголовков и предназначенная для предоставления вам первоклассного доступа к современным интерфейсам API Windows. Дополнительные сведения см. в статье C++/WinRT.

Создание проекта классического приложения

  1. В Visual Studio создайте проект классического приложения для Windows с именем MyDesktopWin32App. Доступ к шаблону этого проекта можно получить, используя фильтры для проекта Рабочий стол, C++ и Windows.

  2. В обозревателе решений щелкните правой кнопкой мыши узел решения, выберите команду Изменить целевую платформу решения, выберите 10.0.18362.0 или более позднюю версию пакета SDK, а затем нажмите кнопку ОК.

  3. Установите пакет NuGet Microsoft.Windows.CppWinRT, чтобы включить поддержку C++/WinRT в проекте.

    1. Щелкните правой кнопкой мыши проект MyDesktopWin32App в обозревателе решений и выберите пункт Manage NuGet Packages (Управление пакетами NuGet).
    2. Перейдите на вкладку Обзор, найдите пакет Microsoft.Windows.CppWinRT и установите последнюю версию этого пакета.
  4. В окне Manage NuGet Packages (Управление пакетами NuGet) установите следующие дополнительные пакеты NuGet:

  5. Добавьте ссылку на метаданные среды выполнения Windows:

    1. В Обозревателе решений щелкните правой кнопкой мыши узел Ссылки проекта и выберите команду Добавить ссылку.
    2. Нажмите кнопку Обзор в нижней части страницы и перейдите к папке UnionMetadata по пути установки пакета SDK. По умолчанию пакет SDK будет установлен в C:\Program Files (x86)\Windows Kits\10\UnionMetadata.
    3. Затем выберите папку с именем, которое соответствует целевой версии Windows (например, 10.0.18362.0). В этой папке выберите файл Windows.winmd.
    4. Нажмите кнопку ОК, чтобы закрыть диалоговое окно Добавление ссылки.
  6. Запустите сборку решения и убедитесь, что она проходит успешно.

Создание проекта приложения UWP

Теперь добавьте проект приложения UWP (C++/WinRT) в решение и внесите некоторые изменения в конфигурацию этого проекта. Далее в этом пошаговом руководстве вы добавите код в этот проект, чтобы внедрить настраиваемый элемент управления WinRT XAML и определить экземпляр класса Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication.

  1. В обозревателе решений, щелкните правой кнопкой мыши по узлу решения и выберите Добавить ->Новый проект.

  2. Добавьте в решение проект пустого приложения (C++/WinRT). Присвойте проекту имя MyUWPApp и убедитесь, что в качестве целевой и минимальной версии используется Windows 10 версии 1903 или более поздней.

  3. Установите пакет NuGet Microsoft.Toolkit.Win32.UI.XamlApplication в проект MyUWPApp. Пакет определяет класс Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication, который будет использоваться позднее в рамках этого пошагового руководства.

    1. Щелкните правой кнопкой мыши проект MyUWPApp и выберите пункт Manage NuGet Packages (Управление пакетами NuGet).
    2. Перейдите на вкладку Обзор, найдите пакет Microsoft.Toolkit.Win32.UI.XamlApplication и установите последнюю стабильную версию этого пакета.
  4. Щелкните правой кнопкой мыши узел MyUWPApp и выберите пункт Свойства. На странице Общие свойства ->C++/WinRT, установите значение для свойства Уровень детализации значение нормальная, затем нажмите Применить. По завершении страница свойств должна выглядеть следующим образом:

    C++/WinRT project properties

  5. На странице Свойства конфигурации ->Общие окна свойств, задайте Тип конфигурации для динамической библиотеки (.dll), затем нажмите ОК, чтобы закрыть окно свойств.

    General project properties

  6. Добавьте исполняемый файл заполнителя в проект MyUWPApp. Этот исполняемый файл заполнителя необходим для создания необходимых файлов проекта и правильной сборки проекта в Visual Studio.

    1. В обозревателе решений, щелкните правой кнопкой мыши по узлу проекта MyUWPApp и выберите Добавить ->Новый элемент.

    2. В диалоговом окне Добавление нового элемента выберите раздел Служебная программа на панели слева, а затем щелкните Текстовый файл (.txt). Введите имя placeholder.exe и нажмите кнопку Добавить. Add text file

    3. В обозревателе решений выберите файл placeholder.exe. В окне Свойства убедитесь, что для свойства Содержимое установлено значение True.

    4. В обозревателе решений щелкните правой кнопкой мыши файл Package.appxmanifest в проекте MyUWPApp, выберите команду Открыть с помощью, а затем Редактор (текстовый) XML и нажмите кнопку ОК.

    5. Найдите элемент <Приложение> и измените значение для атрибута Исполняемый файл на placeholder.exe. По завершении элемент <Приложение> должен выглядеть примерно так:

      <Application Id="App" Executable="placeholder.exe" EntryPoint="MyUWPApp.App">
        <uap:VisualElements DisplayName="MyUWPApp" Description="Project for a single page C++/WinRT Universal Windows Platform (UWP) app with no predefined layout"
          Square150x150Logo="Assets\Square150x150Logo.png" Square44x44Logo="Assets\Square44x44Logo.png" BackgroundColor="transparent">
          <uap:DefaultTile Wide310x150Logo="Assets\Wide310x150Logo.png">
          </uap:DefaultTile>
          <uap:SplashScreen Image="Assets\SplashScreen.png" />
        </uap:VisualElements>
      </Application>
      
    6. Сохраните и закройте файл Package.appxmanifest.

  7. В обозревателе решений щелкните правой кнопкой мыши узел MyUWPApp и выберите команду Выгрузить проект.

  8. Щелкните правой кнопкой мыши узел MyUWPApp и выберите MyUWPApp.vcxproj.

  9. Найдите элемент <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" /> и замените его ниже указанным XML-кодом. Этот XML-код добавляет несколько новых свойств непосредственно перед элементом.

    <PropertyGroup Label="Globals">
        <WindowsAppContainer>true</WindowsAppContainer>
        <AppxGeneratePriEnabled>true</AppxGeneratePriEnabled>
        <ProjectPriIndexName>App</ProjectPriIndexName>
        <AppxPackage>true</AppxPackage>
    </PropertyGroup>
    <Import Project="$(VCTargetsPath)\Microsoft.Cpp.Default.props" />
    
  10. Сохраните и закройте файл проекта.

  11. В обозревателе решений щелкните правой кнопкой мыши узел MyUWPApp и выберите команду Перезагрузить проект.

Настроить решение

В этом разделе вы обновите решение, содержащее все проекты, чтобы настроить зависимости проекта и свойства сборки, необходимые для правильной сборки проектов.

  1. В обозревателе решений щелкните правой кнопкой мыши узел решения и добавьте новый XML-файл с именем Solution.props.

  2. Добавьте следующий XML-код в файл Solution.props.

    <?xml version="1.0" encoding="utf-8"?>
    <Project xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
      <PropertyGroup>
        <IntDir>$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</IntDir>
        <OutDir>$(SolutionDir)\bin\$(Platform)\$(Configuration)\$(MSBuildProjectName)\</OutDir>
        <GeneratedFilesDir>$(IntDir)Generated Files\</GeneratedFilesDir>
      </PropertyGroup>
    </Project>
    
  3. В меню Просмотр, щелкните мышью подиспетчеру свойств (в зависимости от конфигурации этот параметр может находится в разделе Просмотр ->Другие Windows).

  4. В окне диспетчера свойств щелкните правой кнопкой мыши MyDesktopWin32App и выберите команду Добавить существующую страницу свойств. Перейдите в только что добавленный файл Solution.props и щелкните Открыть.

  5. Повторите предыдущий шаг, чтобы добавить файл Solution.props в проект MyUWPApp в окне диспетчера свойств.

  6. Закройте окно диспетчера свойств.

  7. Убедитесь, что изменения на странице свойств сохранены правильно. В обозревателе решений щелкните правой кнопкой мыши проект MyDesktopWin32App и выберите пункт Свойства. Последовательно выберите Свойства конфигурации ->Общие и подтвердите, что свойстваВыходной каталог и Промежуточный каталог имеют значения, добавленные вами в файл Solution.props. Вы также можете проверить значения для проекта MyUWPApp. Project properties

  8. В обозревателе решений щелкните правой кнопкой мыши узел решения и выберите пункт Зависимости проектов. В раскрывающемся списке Проекты убедитесь, что выбран MyDesktopWin32App, и выберите MyUWPApp в списке Depends On (Зависит от). Project dependencies

  9. Нажмите кнопку ОК.

Добавление кода в проект приложения UWP

Теперь вы готовы добавить код в проект MyUWPApp, чтобы выполнить следующие задачи:

  • Реализация пользовательского элемента управления WinRT XAML Далее в этом пошаговом руководстве вы добавите код, который размещает этот элемент управления в проекте MyDesktopWin32App.
  • Определите тип, производный от класса Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication в наборе средств сообщества Windows.

Определение пользовательского элемента управления WinRT XAML

  1. В обозревателе решений, щелкните правой кнопкой мыши файл MyUWPApp выберите Добавить ->Новый элемент. Выберите узел Visual C++ в левой области, затем Blank User Control (C++/WinRT) (Пустой пользовательский элемент управления (C++/WinRT)), назовите его MyUserControl и щелкните Добавить.

  2. В редакторе XAML замените содержимое файла MyUserControl.XAML на следующий XAML-код, а затем сохраните файл:

    <UserControl
        x:Class="MyUWPApp.MyUserControl"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:MyUWPApp"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        mc:Ignorable="d">
    
        <StackPanel HorizontalAlignment="Center" Spacing="10" 
                    Padding="20" VerticalAlignment="Center">
            <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" 
                           Text="Hello from XAML Islands" FontSize="30" />
            <TextBlock HorizontalAlignment="Center" Margin="15" TextWrapping="Wrap"
                           Text="😍❤💋🌹🎉😎�🐱‍👤" FontSize="16" />
            <Button HorizontalAlignment="Center" 
                    x:Name="Button" Click="ClickHandler">Click Me</Button>
        </StackPanel>
    </UserControl>
    

Определение класса XamlApplication

Затем замените класс App по умолчанию в проекте MyUWPApp производным от класса Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication, предоставляемым в наборе средств сообщества Windows. Этот класс поддерживает интерфейс IXamlMetadataProvider, который позволяет приложению обнаруживать и загружать метаданные для настраиваемых элементов управления WinRT XAML в сборках в текущем каталоге приложения во время выполнения. Этот класс также инициализирует платформу WinRT XAML для текущего потока. Позднее в рамках этого пошагового руководства вы обновите проект классического приложения, чтобы создать экзепляр этого класса.

Примечание.

Каждое решение, использующее XAML Islands, может содержать только один проект, определяющий объект XamlApplication. Все пользовательские элементы управления WinRT XAML в приложении используют один и тот же объект XamlApplication.

  1. В обозревателе решений щелкните правой кнопкой мыши файл MainPage.xaml в проекте MyUWPApp. Выберите команду Убрать, а затем — команду Удалить, чтобы удалить этот файл из проекта без возможности восстановления.

  2. В проекте MyUWPApp разверните файл App.xaml.

  3. Замените содержимое файлов App.xaml, App.cpp, App.h и App.idl кодом, указанным ниже.

    • App.xaml:

      <Toolkit:XamlApplication
          x:Class="MyUWPApp.App"
          xmlns:Toolkit="using:Microsoft.Toolkit.Win32.UI.XamlHost"
          xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
          xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
          xmlns:local="using:MyUWPApp">
      </Toolkit:XamlApplication>
      
    • App.idl:

      namespace MyUWPApp
      {
           [default_interface]
           runtimeclass App : Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication
           {
              App();
           }
      }
      
    • App.h:

      #pragma once
      #include "App.g.h"
      #include "App.base.h"
      namespace winrt::MyUWPApp::implementation
      {
          class App : public AppT2<App>
          {
          public:
              App();
              ~App();
          };
      }
      namespace winrt::MyUWPApp::factory_implementation
      {
          class App : public AppT<App, implementation::App>
          {
          };
      }
      
    • App.cpp:

      #include "pch.h"
      #include "App.h"
      #include "App.g.cpp"
      using namespace winrt;
      using namespace Windows::UI::Xaml;
      namespace winrt::MyUWPApp::implementation
      {
          App::App()
          {
              Initialize();
              AddRef();
              m_inner.as<::IUnknown>()->Release();
          }
          App::~App()
          {
              Close();
          }
      }
      

      Примечание.

      #include "App.g.cpp"Инструкция необходима, когда для свойства Оптимизирован на странице Общие свойства проекта ->C++/WinRT в свойствах проекта установлено значение Да. Это значение по умолчанию для новых проектов C++/WinRT. Дополнительные сведения о влиянии свойства Оптимизирован см. в этом разделе.

  4. Добавьте новый файл заголовка в проект MyUWPApp с именем app.base.h.

  5. Добавьте следующий код в файл app.base.h, сохраните файл и закройте его.

    #pragma once
    namespace winrt::MyUWPApp::implementation
    {
        template <typename D, typename... I>
        struct App_baseWithProvider : public App_base<D, ::winrt::Windows::UI::Xaml::Markup::IXamlMetadataProvider>
        {
            using IXamlType = ::winrt::Windows::UI::Xaml::Markup::IXamlType;
            IXamlType GetXamlType(::winrt::Windows::UI::Xaml::Interop::TypeName const& type)
            {
                return _appProvider.GetXamlType(type);
            }
            IXamlType GetXamlType(::winrt::hstring const& fullName)
            {
                return _appProvider.GetXamlType(fullName);
            }
            ::winrt::com_array<::winrt::Windows::UI::Xaml::Markup::XmlnsDefinition> GetXmlnsDefinitions()
            {
                return _appProvider.GetXmlnsDefinitions();
            }
        private:
            bool _contentLoaded{ false };
            winrt::MyUWPApp::XamlMetaDataProvider _appProvider;
        };
        template <typename D, typename... I>
        using AppT2 = App_baseWithProvider<D, I...>;
    }
    
  6. Запустите сборку решения и убедитесь, что она проходит успешно.

Настройка проекта классического приложения для использования типов настраиваемых элементов управления

Прежде чем приложение MyDesktopWin32App разместит настраиваемый элемент управления WinRT XAML в XAML Island, в приложении необходимо настроить использование типов настраиваемых элементов управления из проекта MyUWPApp. Это можно сделать двумя способами, и после ознакомления с этим пошаговым руководством вы можете выбрать любой из них.

Вариант 1. Упаковка приложения с помощью MSIX

Вы можете упаковать приложение в пакет MSIX для развертывания. MSIX — это современная технология упаковки приложений для Windows. В ее основе лежат технологии установки MSI, APPX, App-V и ClickOnce.

  1. Добавьте новый проект упаковки приложений Windows в свое решение. При создании проекта назовите его MyDesktopWin32Project и выберите Windows 10 версии 1903 (10.0; сборка 18362) в качестве целевой и минимальной версии.

  2. В проекте упаковки щелкните правой кнопкой мыши узел Приложения и выберите команду Добавить ссылку. В списке проектов установите флажок рядом с проектом MyDesktopWin32App и нажмите кнопку ОК. Reference project

  3. Сведения о распространении и развертывании пакета см. в статье Управление развертыванием MSIX.

Примечание.

Если вы решили не упаковывать приложение в пакет MSIX для развертывания, на компьютерах с запущенными приложениями должна быть установлена среда выполнения Visual C++.

Вариант 2. Создание манифеста приложения

Можно добавить манифест в приложение.

  1. Щелкните правой кнопкой мыши по проекту MyDesktopWin32App и выберите Добавить ->Новый элемент.

  2. В диалоговом окне Добавление нового элемента щелкните Web (Веб) в левой области и выберите XML-файл (.xml).

  3. Назовите новый файл app.manifest и щелкните Добавить.

  4. Замените содержимое нового файла XML-кодом, указанным ниже. Этот XML-код регистрирует типы настраиваемых элементов управления в проекте MyUWPApp.

    <?xml version="1.0" encoding="utf-8"?>
    <assembly
     xmlns="urn:schemas-microsoft-com:asm.v1"
     xmlns:asmv3="urn:schemas-microsoft-com:asm.v3"
     manifestVersion="1.0">
      <asmv3:file name="MyUWPApp.dll">
        <activatableClass
            name="MyUWPApp.App"
            threadingModel="both"
            xmlns="urn:schemas-microsoft-com:winrt.v1" />
        <activatableClass
            name="MyUWPApp.XamlMetadataProvider"
            threadingModel="both"
            xmlns="urn:schemas-microsoft-com:winrt.v1" />
        <activatableClass
            name="MyUWPApp.MyUserControl"
            threadingModel="both"
            xmlns="urn:schemas-microsoft-com:winrt.v1" />
      </asmv3:file>
    </assembly>
    

Настройка дополнительных свойств проекта классического приложения

Далее обновите проект MyDesktopWin32App, чтобы определить макрос для дополнительных каталогов включаемых файлов и настроить дополнительные свойства.

  1. В обозревателе решений щелкните правой кнопкой мыши проект MyDesktopWin32App и выберите команду Выгрузить проект.

  2. Щелкните правой кнопкой мыши MyDesktopWin32App (Unloaded) (MyDesktopWin32App (Выгружен)) и выберите команду Edit MyDesktopWin32App.vcxproj (Изменить MyDesktopWin32App.vcxproj).

  3. Добавьте XML-код, указанный ниже, напрямую перед закрывающим тегом </Project> в конце файла. Затем сохраните и закройте файл.

      <!-- Configure these for your UWP project -->
      <PropertyGroup>
        <AppProjectName>MyUWPApp</AppProjectName>
      </PropertyGroup>
      <PropertyGroup>
        <AppIncludeDirectories>$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(AppProjectName)\;$(SolutionDir)\obj\$(Platform)\$(Configuration)\$(AppProjectName)\Generated Files\;</AppIncludeDirectories>
      </PropertyGroup>
      <ItemGroup>
        <ProjectReference Include="..\$(AppProjectName)\$(AppProjectName).vcxproj" />
      </ItemGroup>
      <!-- End Section-->
    
  4. В обозревателе решений щелкните правой кнопкой мыши MyDesktopWin32App (unloaded) (MyDesktopWin32App (выгружен)) и выберите команду Перезагрузить проект.

  5. Щелкните правой кнопкой мыши по проекту MyDesktopWin32App, выберите Свойства, и разверните Инструмент манифеста ->Ввод и вывод на левой панели. Задайте для свойства Поддержка DPI значение Поддержка высокого DPI по мониторам. Если это свойство не задано, может возникнуть ошибка конфигурации манифеста в некоторых сценариях с высоким количеством точек на дюйм.

    Screenshot of the C/C++ project settings.

  6. Нажмите кнопку ОК, чтобы закрыть диалоговое окно Страницы свойств.

Размещение настраиваемого элемента управления WinRT XAML в проекте классического приложения

Теперь можно добавить код в проект MyDesktopWin32App для размещения настраиваемого элемента управления WinRT XAML, определенного ранее в проекте MyUWPApp.

  1. В проекте MyDesktopWin32App откройте файл framework.h и закомментируйте строку кода, указанную ниже. По завершении сохраните файл.

    #define WIN32_LEAN_AND_MEAN
    
  2. Откройте файл MyDesktopWin32App.h и замените содержимое этого файла кодом, указанным ниже, чтобы создать ссылки на необходимые заголовочные файлы C++/WinRT. По завершении сохраните файл.

    #pragma once
    
    #include "resource.h"
    #include <winrt/Windows.Foundation.Collections.h>
    #include <winrt/Windows.system.h>
    #include <winrt/windows.ui.xaml.hosting.h>
    #include <windows.ui.xaml.hosting.desktopwindowxamlsource.h>
    #include <winrt/windows.ui.xaml.controls.h>
    #include <winrt/Windows.ui.xaml.media.h>
    #include <winrt/Windows.UI.Core.h>
    #include <winrt/MyUWPApp.h>
    
    using namespace winrt;
    using namespace Windows::UI;
    using namespace Windows::UI::Composition;
    using namespace Windows::UI::Xaml::Hosting;
    using namespace Windows::Foundation::Numerics;
    using namespace Windows::UI::Xaml::Controls;
    
  3. Откройте файл MyDesktopWin32App.cpp и добавьте следующий код в раздел Global Variables::

    winrt::MyUWPApp::App hostApp{ nullptr };
    winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource _desktopWindowXamlSource{ nullptr };
    winrt::MyUWPApp::MyUserControl _myUserControl{ nullptr };
    
  4. В том же файле добавьте следующий код в раздел Forward declarations of functions included in this code module::

    void AdjustLayout(HWND);
    
  5. В том же файле добавьте следующий код сразу после комментария TODO: Place code here. в функции wWinMain:

    // TODO: Place code here.
    winrt::init_apartment(winrt::apartment_type::single_threaded);
    hostApp = winrt::MyUWPApp::App{};
    _desktopWindowXamlSource = winrt::Windows::UI::Xaml::Hosting::DesktopWindowXamlSource{};
    
  6. В том же файле замените функцию InitInstance по умолчанию на следующий код:

    BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
    {
        hInst = hInstance; // Store instance handle in our global variable
    
        HWND hWnd = CreateWindowW(szWindowClass, szTitle, WS_OVERLAPPEDWINDOW,
            CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, nullptr, nullptr, hInstance, nullptr);
    
        if (!hWnd)
        {
            return FALSE;
        }
    
        // Begin XAML Islands walkthrough code.
        if (_desktopWindowXamlSource != nullptr)
        {
            auto interop = _desktopWindowXamlSource.as<IDesktopWindowXamlSourceNative>();
            check_hresult(interop->AttachToWindow(hWnd));
            HWND hWndXamlIsland = nullptr;
            interop->get_WindowHandle(&hWndXamlIsland);
            RECT windowRect;
            ::GetWindowRect(hWnd, &windowRect);
            ::SetWindowPos(hWndXamlIsland, NULL, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_SHOWWINDOW);
            _myUserControl = winrt::MyUWPApp::MyUserControl();
            _desktopWindowXamlSource.Content(_myUserControl);
        }
        // End XAML Islands walkthrough code.
    
        ShowWindow(hWnd, nCmdShow);
        UpdateWindow(hWnd);
    
        return TRUE;
    }
    
  7. В том же файле добавьте следующую новую функцию в конец файла:

    void AdjustLayout(HWND hWnd)
    {
        if (_desktopWindowXamlSource != nullptr)
        {
            auto interop = _desktopWindowXamlSource.as<IDesktopWindowXamlSourceNative>();
            HWND xamlHostHwnd = NULL;
            check_hresult(interop->get_WindowHandle(&xamlHostHwnd));
            RECT windowRect;
            ::GetWindowRect(hWnd, &windowRect);
            ::SetWindowPos(xamlHostHwnd, NULL, 0, 0, windowRect.right - windowRect.left, windowRect.bottom - windowRect.top, SWP_SHOWWINDOW);
        }
    }
    
  8. В том же файле найдите функцию WndProc. Замените обработчик WM_DESTROY по умолчанию в операторе switch на следующий код:

    case WM_DESTROY:
        PostQuitMessage(0);
        if (_desktopWindowXamlSource != nullptr)
        {
            _desktopWindowXamlSource.Close();
            _desktopWindowXamlSource = nullptr;
        }
        break;
    case WM_SIZE:
        AdjustLayout(hWnd);
        break;
    
  9. Сохраните файл.

  10. Запустите сборку решения и убедитесь, что она проходит успешно.

Добавление элемента управления из библиотеки WinUI версии 2 в пользовательский элемент управления

В большинстве случаев элементы управления WinRT XAML выпущены в составе ОС Windows. Разработчики могут использовать их через Windows SDK. В качестве альтернативного варианта можно использовать библиотеку WinUI. Здесь обновленные версии элементов управления WinRT XAML из пакета Windows SDK распределены в пакете NuGet, который не связан с выпусками пакета Windows SDK. Эта библиотека также содержит новые элементы управления, которые не входят в состав пакета Windows SDK и платформы UWP по умолчанию.

В этом разделе показано, как добавить элемент управления WinRT XAML из библиотеки WinUI версии 2 в пользовательский элемент управления.

Примечание.

Сейчас XAML Islands поддерживают только размещение элементов управления из библиотеки WinUI версии 2. Поддержка размещения элементов управления из библиотеки WinUI 3 будет реализована в более позднем выпуске.

  1. В проекте MyUWPApp установите последнюю предварительную или окончательную версию пакета NuGet Microsoft.UI.Xaml.

    • Если ранее при прохождении этого пошагового руководства вы решили упаковать проект MyDesktopWin32App с помощью MSIX, то теперь можете установить предварительную или окончательную версию пакета NugGet Microsoft.UI.Xaml. Упакованные классические приложения могут использовать либо предварительную, либо окончательную версию этого пакета.
    • Если вы решили не упаковывать проект MyDesktopWin32App, то теперь вам нужно установить предварительную версию пакета NuGet Microsoft.UI.Xaml. Неупакованные классические приложения должны использовать предварительную версию этого пакета.
  2. В файле pch.h в этом проекте добавьте следующие инструкции #include и сохраните изменения. Эти инструкции предоставляют необходимый набор заголовков проекции из библиотеки WinUI в проекте. Этот шаг необходим для любого проекта C++/WinRT, использующего библиотеку WinUI. Дополнительные сведения см. в этой статье.

    #include "winrt/Microsoft.UI.Xaml.Automation.Peers.h"
    #include "winrt/Microsoft.UI.Xaml.Controls.Primitives.h"
    #include "winrt/Microsoft.UI.Xaml.Media.h"
    #include "winrt/Microsoft.UI.Xaml.XamlTypeInfo.h"
    
  3. В файле App.xaml в том же проекте добавьте следующий дочерний элемент в элемент <xaml:XamlApplication> и сохраните изменения.

    <Application.Resources>
        <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls" />
    </Application.Resources>
    

    После добавления этого элемента содержимое файла должно выглядеть следующим образом:

    <Toolkit:XamlApplication
        x:Class="MyUWPApp.App"
        xmlns:Toolkit="using:Microsoft.Toolkit.Win32.UI.XamlHost"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:local="using:MyUWPApp">
        <Application.Resources>
            <XamlControlsResources xmlns="using:Microsoft.UI.Xaml.Controls"/>
        </Application.Resources>
    </Toolkit:XamlApplication>
    
  4. В том же проекте откройте файл MyUserControl.xaml и добавьте следующее объявление пространства имен в элемент <UserControl>.

    xmlns:winui="using:Microsoft.UI.Xaml.Controls"
    
  5. В том же файле добавьте элемент <winui:RatingControl /> в качестве дочернего элемента <StackPanel> и сохраните изменения. Этот элемент добавляет экземпляр класса RatingControl из библиотеки WinUI. После добавления этого элемента <StackPanel> должен выглядеть следующим образом.

    <StackPanel HorizontalAlignment="Center" Spacing="10" 
                Padding="20" VerticalAlignment="Center">
        <TextBlock HorizontalAlignment="Center" TextWrapping="Wrap" 
                       Text="Hello from XAML Islands" FontSize="30" />
        <TextBlock HorizontalAlignment="Center" Margin="15" TextWrapping="Wrap"
                       Text="😍❤💋🌹🎉😎�🐱‍👤" FontSize="16" />
        <Button HorizontalAlignment="Center" 
                x:Name="Button" Click="ClickHandler">Click Me</Button>
        <winui:RatingControl />
    </StackPanel>
    
  6. Запустите сборку решения и убедитесь, что она проходит успешно.

Тестирование приложения

Запустите решение и убедитесь, что MyDesktopWin32App открывается в следующем окне:

MyDesktopWin32App app

Следующие шаги

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

Дополнительные сведения о работе с такими сценариями и связанные примеры кода см. в статье Расширенные сценарии использования XAML Islands в классических приложениях C++.