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

Это важно

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

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

Для размещения пользовательского элемента управления XAML UWP вы создадите следующие проекты и компоненты в рамках этого пошагового руководства:

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

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

Требования

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

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

  1. В Visual Studio создайте новый проект Windows Desktop Application с именем MyDesktopWin32App. Шаблон проекта доступен в фильтрах проектов C++, Windows и Desktop.

  2. В Обозреватель решений щелкните правой кнопкой мыши узел решения, щелкните Retarget solution, выберите 10.0.18362.0 или более позднюю версию SDK и затем щелкните OK.

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

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

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

    1. В Обозреватель решений щелкните правой кнопкой мыши узел project References и выберите Add Reference.
    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) в ваше решение и внесите некоторые изменения конфигурации в этот проект. В дальнейшем в этом пошаговом руководстве вы добавите код в этот проект для реализации пользовательского элемента управления XAML UWP и определите экземпляр класса Microsoft.Toolkit.Win32.UI.XamlHost.XamlApplication.

  1. В Обозреватель решений щелкните правой кнопкой мыши узел решения и выберите Add ->New Project.

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

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

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

    Скриншот страницы свойств проекта с выбранными общими свойствами — C++/WinRT, где выделено свойство Verbosity с установленным значением 'normal'.

  5. На странице Configuration Properties ->General окна свойств, задайте Тип конфигурации как Dynamic Library (.dll) и нажмите кнопку OK, чтобы закрыть окно свойств.

    Скриншот страницы свойств проекта с выбранным разделом

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

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

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

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

    4. В Обозреватель решений щелкните правой кнопкой мыши файл Package.appxmanifest в файле MyUWPApp project, выберите Open With и выберите редактор XML (текст и щелкните OK.

    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 и выберите Unload Project.

  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. Сохраните и закройте файл project.

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

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

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

  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 project в окне Property Manager.

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

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

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

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

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

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

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

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

  1. В Обозреватель решений щелкните правой кнопкой мыши MyUWPApp и выберите Add ->New Item. Выберите узел Visual C++ в левой области, затем Пустой пользовательский элемент управления (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 Community Toolkit. Этот класс поддерживает интерфейс IXamlMetadataProvider, который позволяет приложению обнаруживать и загружать метаданные для настраиваемых элементов управления UWP XAML в сборках в текущем каталоге приложения во время выполнения. Этот класс также инициализирует платформу UWP XAML для текущего потока. Далее в этом пошаговом руководстве вы обновите проект для рабочего стола, чтобы создать экземпляр этого класса.

Замечание

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

  1. В Обозреватель решений щелкните правой кнопкой мыши файл MainPage.xaml в файле MyUWPApp project. Щелкните Remove а затем Delete, чтобы окончательно удалить этот файл из project.

  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" необходим, если свойство Optimized на странице Common Properties -> >C++/WinRT в свойствах проекта задано значение Yes. Это значение по умолчанию для новых проектов C++/WinRT. Дополнительные сведения о влиянии свойства Optimized см. в разделе this.

  4. Добавьте новый файл заголовка в MyUWPApp project с именем 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 сможет разместить пользовательский элемент управления XAML UWP в компоненте XAML Island, его необходимо настроить для использования пользовательских типов элементов управления из проекта MyUWPApp. Существует два способа сделать это, и вы можете выбрать любой из вариантов выполнения этого пошагового руководства.

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

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

  1. Добавьте в решение новый проект Windows Application Packaging Project. При создании проекта назовите его MyDesktopWin32Project и выберите Windows 10, версии 1903 (10.0; Сборка 18362) для целевой версии и минимальной версии.

  2. В проекте упаковки щелкните правой кнопкой мыши узел Applications и выберите Add reference. В списке проектов установите флажок рядом с MyDesktopWin32App project и щелкните OK. Скриншот диалогового окна Диспетчера ссылок для проекта упаковки, где текущий проект выбран в качестве ссылки.

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

Замечание

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

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

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

  1. Щелкните правой кнопкой мыши MyDesktopWin32App project выберите Add ->New Item.

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

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

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

    <?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 project и выберите Unload Project.

  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 (отключено) и выберите Перезагрузить проект.

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

    Скриншот страницы свойств текущего проекта с характеристиками конфигурации - Инструмент манифестации - выбранные параметры ввода и вывода, с установленным уровнем DPI Awareness на 'Aware с высоким DPI на монитор'.

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

Разместите пользовательский элемент управления XAML UWP в настольном проекте.

Наконец, вы готовы добавить код в проект MyDesktopWin32App , чтобы разместить пользовательский элемент управления XAML UWP, определенный ранее в проекте MyUWPApp .

  1. В MyDesktopWin32App project откройте файл 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 для UWP в пользовательский элемент управления

Традиционно элементы управления XAML UWP были выпущены в составе ос Windows и предоставлены разработчикам через пакет SDK Windows. Библиотека WinUI 3 — это альтернативный подход, где обновленные версии элементов управления XAML UWP из пакета SDK Windows распределены в пакете NuGet, который не привязан к выпускам пакета SDK Windows. Эта библиотека также содержит новые элементы управления, которые не входят в состав пакета Windows SDK и платформы UWP по умолчанию.

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

Замечание

В настоящее время XAML Islands поддерживает только элементы управления размещением из библиотеки WinUI для UWP. Поддержка элементов управления размещением из библиотеки WinUI будет добавлена в будущем обновлении.

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

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

    #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 в том же project добавьте следующий дочерний элемент в элемент <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. В том же project откройте файл 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, показанное в этом разделе.

Дальнейшие шаги

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

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