Создайте "Hello, World!" Приложение UWP с помощью C++/WinRT

В этой статье приведены сведения о создании приложения Hello, World! на платформе Windows UWP с помощью C++/WinRT. Пользовательский интерфейс приложения определяется на языке XAML.

C++/WinRT — это полностью соответствующая стандартам современная проекция языка C++17 для API среды выполнения Windows (WinRT). Дополнительные сведения и другие пошаговые руководства и примеры кода см. в документации по C++/WinRT. Для начала ознакомьтесь со статьей о начале работы с C++/WinRT.

Настройка Visual Studio для C++/WinRT

Сведения об установке Visual Studio для разработки с использованием C++/WinRT, включая установку и использование расширения C++/WinRT для Visual Studio (VSIX) и пакета NuGet (которые вместе обеспечивают поддержку шаблона проекта и сборки), приведены в разделе Поддержка Visual Studio для C++/WinRT.

Чтобы скачать Visual Studio, перейдите на эту страницу.

Основные сведения о XAML см. в этой статье.

Создание пустого приложения (HelloWorldCppWinRT)

Наше первое приложение Hello World демонстрирует некоторые основные возможности взаимодействия, стилей и макета.

Начните с создания проекта в Microsoft Visual Studio. Создайте проект Пустое приложение (C++/WinRT) и назовите его HelloWorldCppWinRT. Убедитесь, что снят флажок Поместить решение и проект в одном каталоге. В качестве цели выберите последнюю общедоступную (то есть не предварительную) версию Windows SDK.

В следующем разделе этой статьи, вы будете перенаправлены, чтобы создать проект (но не создавайте до тех пор).

Сведения о файлах проекта

Как правило, в папке проекта у каждого файла .xaml разметки XAML есть соответствующий файл .idl, .h и .cpp. Вместе эти файлы компилируются в тип страницы XAML.

Вы можете изменить файл разметки XAML, чтобы создать элементы пользовательского интерфейса, а также привязать эти элементы к источникам данных (эта задача известна как привязка данных). Вы также можете изменить файлы .h и .cpp (а иногда файл .idl), чтобы добавить пользовательскую логику, например, для обработчиков событий страницы XAML.

Рассмотрим некоторые файлы проекта.

  • App.idl, App.xaml, App.h и App.cpp. Эти файлы представляют специализацию приложения класса Windows::UI::Xaml::Application , которая включает точку входа приложения. App.xaml не содержит разметки, относящейся к отдельным страницам, но вы можете добавлять в него стили элементов пользовательского интерфейса, а также любые другие элементы, которые следует сделать доступными с любой страницы. Файлы .h и .cpp содержат обработчики для различных событий жизненного цикла приложения. Обычно сюда добавляется пользовательский код для инициализации приложения при запуске, а также здесь выполняется очистка при приостановке и завершении работы.
  • MainPage.idl, MainPage.xaml, MainPage.h и MainPage.cpp. Эти файлы содержат разметку XAML и реализацию для стандартной главной (начальной) страницы в приложении, которое является классом MainPage среды выполнения. MainPage не поддерживает навигацию, однако предоставляет некоторые стандартный пользовательский интерфейс и обработчик событий для начала работы.
  • pch.h и pch.cpp. Эти файлы представляют предварительно скомпилированный файл заголовка проекта. В pch.h включите все файлы заголовков, которые редко меняются, а затем включите pch.h в другие файлы проекта.

Первый взгляд на код

Классы среды выполнения

Как вы знаете, все классы в приложении универсальной платформы Windows (UWP), написанном на C#, являются типами среды выполнения Windows. Однако при создании типа в приложении C++/WinRT вы можете выбрать, будет ли этот тип типом среды выполнения Windows или обычным классом, структурой или перечислением C++.

Любая страница XAML в проекте должна быть типом среды выполнения Windows. Поэтому MainPage должен быть типом среды выполнения Windows. В частности, это класс среды выполнения. Любой тип, используемый страницей XAML, должен быть типом среды выполнения Windows. Если при написании компонента среды выполнения Windows вы хотите создать тип, который можно использовать из другого приложения, создайте тип среды выполнения Windows. В других случаях можно использовать обычный тип C++. В целом тип среды выполнения Windows можно использовать на любом языке среды выполнения Windows.

Хорошим признаком того, что используется тип среды выполнения Windows, является то, что он определен в .idl-файле на языке MIDL (MIDL). В качестве примера рассмотрим класс MainPage.

// MainPage.idl
namespace HelloWorldCppWinRT
{
    [default_interface]
    runtimeclass MainPage : Windows.UI.Xaml.Controls.Page
    {
        MainPage();
        Int32 MyProperty;
    }
}

Ниже приведена базовая структура реализации класса среды выполнения MainPage и его фабрики активации, как показано в MainPage.h.

// MainPage.h
...
namespace winrt::HelloWorldCppWinRT::implementation
{
    struct MainPage : MainPageT<MainPage>
    {
        MainPage();

        int32_t MyProperty();
        void MyProperty(int32_t value);
        ...
    };
}

namespace winrt::HelloWorldCppWinRT::factory_implementation
{
    struct MainPage : MainPageT<MainPage, implementation::MainPage>
    {
    };
}

Дополнительные сведения о создании классов среды выполнения для заданного типа см. в статье Создание интерфейсов API с помощью C++/WinRT. Дополнительные сведения о соединении между классами среды выполнения и IDL (файлами .idl) см. в статье Элементы управления XAML; привязка к свойству C++/WinRT. В этой статье объясняется процесс написания нового класса среды выполнения, первым шагом которого является добавление в проект нового элемента Midl File (.idl).

Теперь добавим некоторые функциональные возможности в проект HelloWorldCppWinRT.

Шаг 1. Изменение начальной страницы

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

Удалите элемент StackPanel, который там уже есть, и все его содержимое. На его место вставьте следующий код XAML.

<StackPanel x:Name="contentPanel" Margin="120,30,0,0">
    <TextBlock HorizontalAlignment="Left" Text="Hello, World!" FontSize="36"/>
    <TextBlock Text="What's your name?"/>
    <StackPanel x:Name="inputPanel" Orientation="Horizontal" Margin="0,20,0,20">
        <TextBox x:Name="nameInput" Width="300" HorizontalAlignment="Left"/>
        <Button x:Name="inputButton" Content="Say &quot;Hello&quot;"/>
    </StackPanel>
    <TextBlock x:Name="greetingOutput"/>
</StackPanel>

Этот новый элемент StackPanel содержит TextBlock, который запрашивает имя пользователя; TextBox, который принимает имя пользователя; элемент Button и еще один элемент TextBlock.

Так как мы удалили элемент Button с именем myButton, необходимо изъять на него ссылку из кода. Таким образом, в MainPage.cpp удалите строку кода внутри функции MainPage::ClickHandler.

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

UWP app screen, with controls

В приложении можно вводить данные в текстовом поле. Однако если нажать кнопку сейчас, ничего не произойдет.

Шаг 2. Добавление обработчика событий

В MainPage.xaml найдите элемент Button с именем inputButton и объявите обработчик событий для события ButtonBase::Click. Разметка для элемента Button теперь должна выглядеть следующим образом:

<Button x:Name="inputButton" Content="Say &quot;Hello&quot;" Click="inputButton_Click"/>

Реализуйте обработчик событий следующим образом:

// MainPage.h
struct MainPage : MainPageT<MainPage>
{
    ...
    void inputButton_Click(
        winrt::Windows::Foundation::IInspectable const& sender,
        winrt::Windows::UI::Xaml::RoutedEventArgs const& e);
};

// MainPage.cpp
namespace winrt::HelloWorldCppWinRT::implementation
{
    ...
    void MainPage::inputButton_Click(
        winrt::Windows::Foundation::IInspectable const& sender,
        winrt::Windows::UI::Xaml::RoutedEventArgs const& e)
    {
        greetingOutput().Text(L"Hello, " + nameInput().Text() + L"!");
    }
}

Дополнительные сведения см. в статье об обработке событий с помощью делегатов.

Во время реализации имя пользователя извлекается из текстового поля и используется для создания приветствия, которое затем отображается в текстовом блоке greetingOutput.

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

App screen with message display

Шаг 3. Стиль начальной страницы

Выберите тему

Легко настроить внешний вид и удобство работы приложения. По умолчанию ваше приложение использует ресурсы со светлым стилем. Системные ресурсы также включают тему в темных тонах.

Чтобы оценить тему в темных тонах, измените App.xaml и добавьте значение для Application::RequestedTheme.

<Application
    ...
    RequestedTheme="Dark">

</Application>

Мы рекомендуем для приложений, которые главным образом отображают изображения или видео, использовать темную тему, а для приложений с большим объемом текста — светлую тему. Если применяется пользовательская цветовая схема, используйте тему, которая лучше всего сочетается с внешним видом вашего приложения.

Примечание.

Тема применяется при запуске приложения. Тему нельзя изменить во время работы приложения.

Использование системных стилей

В этом разделе мы изменим внешний вид текста (например, увеличим размер шрифта).

В MainPage.xaml найдите элемент What's your name? (Как Вас зовут?)TextBlock. Задайте для свойства Стиль ссылку на ключ системного ресурса BaseTextBlockStyle.

<TextBlock Text="What's your name?" Style="{ThemeResource BaseTextBlockStyle}"/>

BaseTextBlockStyle — это ключ ресурса, который определен в ResourceDictionary в файле \Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<version>\Generic\generic.xaml. Ниже приведены значения свойств, которые задаются этим стилем.

<Style x:Key="BaseTextBlockStyle" TargetType="TextBlock">
    <Setter Property="FontFamily" Value="XamlAutoFontFamily" />
    <Setter Property="FontWeight" Value="SemiBold" />
    <Setter Property="FontSize" Value="14" />
    <Setter Property="TextTrimming" Value="None" />
    <Setter Property="TextWrapping" Value="Wrap" />
    <Setter Property="LineStackingStrategy" Value="MaxHeight" />
    <Setter Property="TextLineBounds" Value="Full" />
</Style>

Также в MainPage.xaml найдите элемент TextBlock с именем greetingOutput. Задайте для свойства Стиль значение BaseTextBlockStyle. Теперь при создании и запуске приложения вы увидите, что внешний вид обоих блоков текста изменился (например, увеличился размер шрифта).

Шаг 4. Адаптация пользовательского интерфейса к различным размерам окна

Теперь мы будем динамически адаптировать пользовательский интерфейс к изменяющимся размерам окна, чтобы он хорошо выглядел на устройствах с небольшим размером дисплея. Для этого добавьте раздел VisualStateManager в MainPage.xaml. Вы определите различные визуальные состояния для различных размеров окон, после чего сможете задать свойства, которые будут применяться для каждого из этих визуальных состояний.

Настройка макета пользовательского интерфейса

Добавьте этот блок XAML в качестве первого дочернего элемента корневого элемента StackPanel.

<StackPanel ...>
    <VisualStateManager.VisualStateGroups>
        <VisualStateGroup>
            <VisualState x:Name="wideState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="641" />
                </VisualState.StateTriggers>
            </VisualState>
            <VisualState x:Name="narrowState">
                <VisualState.StateTriggers>
                    <AdaptiveTrigger MinWindowWidth="0" />
                </VisualState.StateTriggers>
                <VisualState.Setters>
                    <Setter Target="contentPanel.Margin" Value="20,30,0,0"/>
                    <Setter Target="inputPanel.Orientation" Value="Vertical"/>
                    <Setter Target="inputButton.Margin" Value="0,4,0,0"/>
                </VisualState.Setters>
            </VisualState>
        </VisualStateGroup>
    </VisualStateManager.VisualStateGroups>
    ...
</StackPanel>

Выполните сборку и запустите приложение. Обратите внимание, что пользовательский интерфейс выглядит так же, как и раньше, пока ширина окна не станет меньше 641 аппаратно-независимого пикселя (DIP). На этом этапе применяется визуальное состояние narrowState и вместе с ним все методы задания свойств, определенные для этого состояния.

В VisualState с именем wideState AdaptiveTrigger с его свойством MinWindowWidth задано значение 641. Это означает, что состояние применяется только в том случае, если ширина окна не меньше 641 DIPs. Вы не указываете никакие объекты Setter для этого состояния, поэтому оно использует свойства макета, заданные в XAML для содержимого страницы.

Второй VisualState narrowStateимеет адаптивныйtrigger со свойством MinWindowWidth значение 0. Это состояние применяется, если ширина окна превышает 0, но менее 641 DIPs. Для 641 DIP-пикселя применяется wideState. В narrowState необходимо указать объекты Setter, чтобы изменить свойства макета элементов управления в пользовательском интерфейсе.

  • Вы уменьшаете левое поле элемента contentPanel со 120 до 20.
  • Вы изменяете Orientation для элемента inputPanel с Horizontal на Vertical.
  • Вы добавляете верхнее поле высотой 4 DIP к элементу inputButton.

Итоги

В данном пошаговом руководстве было продемонстрировано, как добавлять содержимое в универсальное приложение для Windows, как добавлять интерактивные возможности и изменять внешний вид пользовательского интерфейса.