C++/WinRT를 사용하여 "Hello, World!" C++/WinRT를 사용하는 UWP 앱

이 항목에서는 C++/WinRT를 사용하여 Windows UWP(유니버설 Windows 플랫폼) "Hello, World!" 앱을 만드는 과정을 안내합니다. 이 앱의 UI(사용자 인터페이스)는 XAML(Extensible Application Markup Language)을 사용하여 정의됩니다.

C++/WinRT는 WinRT(Windows Runtime) API를 위한 완전한 현대식 표준 C++17 언어 프로젝션입니다. 자세한 내용과 추가 연습 및 코드 예제는 C++ /WinRT 설명서를 참조하세요. 시작하는 데 도움이 되는 토픽은 C++/WinRT 시작입니다.

C++/WinRT용 Visual Studio 설정

프로젝트 템플릿 및 빌드 지원을 함께 제공하는 C++/WinRT Visual Studio 확장(VSIX) 및 NuGet 패키지를 설치하고 사용하는 방법을 포함하는 C++/WinRT용 Visual Studio 개발 설정에 대한 자세한 내용은 C++/WinRT에 대한 Visual Studio 지원을 참조하세요.

Visual Studio를 다운로드하려면 다운로드를 참조하세요.

XAML에 대한 소개는 XAML 개요를 참조하세요.

비어 있는 앱(HelloWorldCppWinRT) 만들기

첫 번째로 작성할 앱은 대화형 작업, 레이아웃 및 스타일의 일부 기본 기능을 보여주는 "Hello, World!" 앱입니다.

먼저 Microsoft Visual Studio에서 새 프로젝트를 만듭니다. 비어 있는 앱(C++/WinRT) 프로젝트를 만들고 이름을 HelloWorldCppWinRT라고 지정합니다. 솔루션 및 프로젝트를 같은 디렉터리에 배치를 선택하지 않아야 합니다. 일반적으로 사용 가능한 최신(미리 보기 아님) 버전의 Windows SDK를 대상으로 합니다.

이 항목의 뒤쪽 섹션에서는 프로젝트(단, 다음까지 빌드하지 않음)를 빌드하게 됩니다.

프로젝트 파일 정보

일반적으로 프로젝트 폴더의 각 .xaml(XAML 태그) 파일에는 해당 .idl, .h.cpp 파일이 들어 있습니다. 이러한 파일은 XAML 페이지 형식으로 컴파일됩니다.

XAML 태그 파일을 수정하여 UI 요소를 만들 수 있으며, 이러한 요소를 데이터 소스에 바인딩할 수 있습니다(이 작업을 데이터 바인딩이라고 함). XAML 페이지의 사용자 지정 논리(예: 이벤트 처리기)를 추가하도록 .h.cpp 파일(경우에 따라 .idl 파일)을 수정합니다.

프로젝트 파일을 살펴보겠습니다.

  • App.idl, App.xaml, App.hApp.cpp. 이러한 파일은 앱의 진입점을 포함하는 Windows::UI::Xaml::Application 클래스의 앱 특수화를 나타냅니다. App.xaml은 페이지 관련 태그를 포함하지 않지만, 여기서 사용자 인터페이스 요소 스타일과 모든 페이지에서 액세스할 수 있도록 만들려는 다른 요소를 추가할 수 있습니다. .h.cpp 파일에는 다양한 애플리케이션 수명 주기 이벤트에 대한 처리기가 포함되어 있습니다. 일반적으로 앱이 시작될 때 앱을 초기화하고 앱이 일시 중단되거나 종료될 때 정리를 수행하는 사용자 지정 코드를 여기에 추가할 수 있습니다.
  • MainPage.idl, MainPage.xaml, MainPage.hMainPage.cpp. 앱의 기본 주(시작) 페이지 형식에 대한 XAML 태그 및 구현인 MainPage 런타임 클래스를 포함합니다. MainPage에서는 탐색을 지원하지 않지만, 시작하는 데 필요한 몇 가지 기본 UI와 이벤트 처리기를 제공합니다.
  • pch.hpch.cpp. 이러한 파일은 프로젝트의 미리 컴파일된 헤더 파일을 나타냅니다. pch.h에서, 자주 변경되지 않는 헤더 파일을 포함한 다음, 프로젝트의 다른 파일에 pch.h를 포함합니다.

코드 개요

런타임 클래스

아시다시피, C#으로 작성된 UWP(유니버설 Windows 플랫폼) 앱의 모든 클래스는 Windows 런타임 형식입니다. 그러나 C++/WinRT 애플리케이션에서 형식을 작성하는 경우 해당 형식이 Windows 런타임 형식인지, 아니면 일반 C++ 클래스/구조체/열거형인지 선택할 수 있습니다.

프로젝트의 모든 XAML 페이지 형식은 Windows 런타임 형식이어야 합니다. 따라서 MainPage는 Windows 런타임 형식입니다. 특히 런타임 클래스입니다. XAML 페이지에서 사용하는 형식도 Windows 런타임 형식이어야 합니다. Windows 런타임 구성 요소를 작성할 때 다른 앱에서 사용할 수 있는 형식을 작성하려면 Windows 런타임 형식을 작성해야 합니다. 그 외의 경우에는 일반 C++ 형식이어도 됩니다. 일반적으로 Windows 런타임 형식은 모든 Windows 런타임 언어를 통해 사용할 수 있습니다.

형식이 Windows 런타임 형식이라는 것을 보여주는 좋은 증거 중 하나는 형식이 인터페이스 정의 언어(.idl) 파일 내부의 MIDL(Microsoft Interface Definition Language)에 정의된다는 것입니다. MainPage를 예로 들어 살펴보겠습니다.

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

다음은 MainPage.h에 표시된 것처럼 MainPage 런타임 클래스 및 해당 활성화 팩터리 구현의 기본 구조입니다.

// 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>
    {
    };
}

특정 형식의 런타임 클래스를 작성해야 하는지 여부에 대한 자세한 내용은 C++/WinRT를 통한 API 작성 항목을 참조하세요. XAML 컨트롤, C++/WinRT 속성에 바인딩 토픽에서 런타임 클래스와 IDL(.idl 파일) 간 연결에 대한 자세한 내용을 읽고 따라 하세요. 해당 항목에서는 새로운 런타임 클래스 작성 프로세스를 진행하며, 첫 번째 단계는 새 Midl 파일(.idl) 항목을 프로젝트에 추가하는 것입니다.

이제 HelloWorldCppWinRT 프로젝트에 몇 가지 기능을 추가해 보겠습니다.

1단계 시작 페이지 수정

UI(사용자 인터페이스)를 형성하는 컨트롤을 작성할 수 있도록 솔루션 탐색기에서 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 요소가 있습니다.

myButton이라는 버튼을 삭제했으므로, 코드에서 이 버튼에 대한 참조를 제거해야 합니다. 따라서 MainPage.cpp에서 MainPage::ClickHandler 함수 내부의 코드 줄을 삭제합니다.

이제 매우 간단한 유니버설 Windows 앱을 만들었습니다. UWP 앱의 모양을 확인하려면 앱을 빌드하고 실행합니다.

UWP app screen, with controls

앱에서 텍스트 상자에 내용을 입력할 수 있습니다. 그러나 아직은 버튼을 클릭해도 아무것도 수행되지 않습니다.

2단계. 이벤트 처리기 추가

MainPage.xaml에서 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에서 "이름이 무엇인가요?." TextBlock을 찾습니다. Style 속성을 BaseTextBlockStyle 시스템 리소스 키의 참조로 설정합니다.

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

BaseTextBlockStyle\Program Files (x86)\Windows Kits\10\DesignTime\CommonConfiguration\Neutral\UAP\<version>\Generic\generic.xamlResourceDictionary에 정의되는 리소스 키입니다. 해당 스타일을 사용하여 설정되는 속성 값은 다음과 같습니다.

<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에서 greetingOutput이라는 TextBlock을 찾습니다. 마찬가지로 Style 속성을 BaseTextBlockStyle로 설정합니다. 지금 앱을 빌드하고 실행하면 두 텍스트 블록의 모양이 변경된 것을 볼 수 있습니다(예를 들어 글꼴 크기가 더 크게 변경됨).

4단계. UI를 다양한 창 크기에 맞게 조정

작은 디스플레이를 사용하는 디바이스에서도 UI가 제대로 보이도록, 바뀌는 창 크기에 맞게 UI를 동적으로 조정하겠습니다. 이렇게 하려면 VisualStateManager 섹션을 MainPage.xaml에 추가합니다. 여러 창 크기에 대한 다양한 시각적 상태를 정의한 다음, 각 시각적 상태에 적용되도록 속성을 설정합니다.

UI 레이아웃 조정

이 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(디바이스 독립적 픽셀)보다 좁은 크기로 조정되기 전에는 UI가 이전과 동일하게 표시됩니다. 이제 narrowState 시각적 상태 및 해당 상태에 대해 정의된 모든 속성 setter가 적용됩니다.

wideState라는 VisualState에는 해당 MinWindowWidth 속성이 641로 설정된 AdaptiveTrigger가 있습니다. 즉, 창 너비가 최소값인 641 DIP(장치 독립적인 픽셀)보다 작지 않은 경우에만 상태가 적용됩니다. 이 상태에 대해 어떤 Setter 개체도 정의하지 않으므로, 페이지 내용에 대한 XAML에 정의된 레이아웃 속성이 사용됩니다.

두 번째 VisualState, narrowState에는 해당 MinWindowWidth 속성이 0으로 설정된 AdaptiveTrigger가 있습니다. 창 너비가 0보다 크지만 641 DIP보다는 작은 경우에 이 상태가 적용됩니다. 정확히 641 DIP에서 wideState가 적용됩니다. narrowState 상태에서는 UI에 있는 컨트롤의 레이아웃 속성을 변경하도록 Setter 개체를 정의합니다.

  • contentPanel 요소의 왼쪽 여백을 120에서 20으로 줄입니다.
  • inputPanel 요소의 OrientationHorizontal에서 Vertical로 변경합니다.
  • 4 DIP의 상단 여백을 inputButton 요소에 추가합니다.

요약

이 연습에서는 Windows 유니버설 앱에 콘텐츠를 추가하는 방법, 대화형 작업을 추가하는 방법 및 UI 모양을 변경하는 방법에 대해 알아보았습니다.