버튼 클릭 및 속성 바인딩 구현

지난 수업에서 XAML에 버튼을 추가하고 이벤트를 생성했습니다. 먼저 구현한 기능은 버튼을 클릭하면 버튼 텍스트가 변경되는 로직입니다.

먼저 XAML 파일로 돌아와 버튼에 x:Name="btnAdd" 이름을 지정합니다. 이렇게 하면 백엔드 C++ 코드에서 해당 버튼 객체를 조작할 수 있습니다.

<Grid>
    <Button x:Name="btnAdd" Content="Click Me" HorizontalAlignment="Center" VerticalAlignment="Center" Click="OnButtonClick"/>
</Grid>Code language: HTML, XML (xml)

그 다음 MainWindow.xaml.cpp 안의 OnButtonClick 구현 함수로 이동합니다.

위에서 선언한 btnAdd를 통해 버튼 객체를 직접 가져올 수 있습니다.

클릭 시 Content 속성을 “Welcome to FoxDevelop.com”으로 변경합니다.

이제 프로젝트를 실행해 확인합니다.

void winrt::WinuiCppDemo::implementation::MainWindow::OnButtonClick(winrt::Windows::Foundation::IInspectable const& sender, 
winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    btnAdd().Content(box_value(L"Welcome to FoxDevelop.com"));
}
Code language: C++ (cpp)

클릭으로 UI 속성을 수정할 수 있는 것을 확인했습니다. 다음으로 클릭 횟수를 기록하는 정수 속성을 만들어 클릭할 때마다 값을 1씩 증가시키고, 이 속성을 XAML의 텍스트블록에 바인딩해 UI가 자동으로 최신 값을 표시하도록 구현합니다.

속성 바인딩

이전 예제 코드의 간섭을 피하려면 빈 새 프로젝트를 생성해서 실습하는 것을 권장합니다.

아래 단계대로 진행합니다.

XAML을 수정하고 TextBlock을 추가합니다.

<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="WinuiDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinuiDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="WinuiDemo">

    <Grid>
        <TextBlock Text="{x:Bind MyProperty}" FontSize="24"/>
    </Grid>
</Window>
Code language: C++ (cpp)

그 다음 .cpp 파일에서 MyProperty가 숫자를 반환하도록 작성합니다.

namespace winrt::WinuiDemo::implementation
{
    int32_t MainWindow::MyProperty()
    {
        return 100;
    }

    void MainWindow::MyProperty(int32_t /* value */)
    {
        throw hresult_not_implemented();
    }
}
Code language: C++ (cpp)

빌드 후 실행합니다.

개발 환경에 따라 아래 오류가 발생하고 빌드 프로세스가 멈춰버릴 수 있습니다.

Build started at 14:42...
1>------ Build started: Project: WinuiCppDemo, Configuration: Debug x64 ------
1>WindowsAppSDKMLDeploymentMode=Framework
1>MainWindow.xaml.cpp

오류 내용은 다음과 같습니다.

#error directive: "C++/WinRT no longer supports pre-standardization coroutines. 
If you use co_await, switch to /await:strict or upgrade to C++20. If you do not,
 remove /await from the compiler flags."Code language: PHP (php)

C++20으로 업그레이드

WinUI 3와 C++/WinRT는 표준 코루틴 기반으로 제작되었으며 C++20으로 업그레이드하면 유지보수가 훨씬 수월해집니다.

프로젝트 속성 → C/C++ → 언어 → C++ 언어 표준 메뉴에서 C++20을 선택합니다.

다시 빌드를 실행합니다. 빌드 시간이 매우 오래 걸리며 D:\Demos\WinuiDemo\WinuiDemo\x64\Debug 경로에 1.3GB 크기의 중간 파일들이 생성됩니다. PC 사양에 따라 소요 시간은 달라집니다. 빌드 성공 후 앱을 실행하면 화면에 숫자 100이 표시됩니다.

int32_t MainWindow::MyProperty()
    {
        return 100;
    }Code language: C++ (cpp)

화면에는 이 속성이 반환하는 값이 출력됩니다.

버튼 클릭 카운터 증가 기능 구현

이제 버튼을 추가하고 클릭 이벤트를 연결합니다.

<?xml version="1.0" encoding="utf-8"?>
<Window
    x:Class="WinuiDemo.MainWindow"
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
    xmlns:local="using:WinuiDemo"
    xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
    xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
    mc:Ignorable="d"
    Title="WinuiDemo">

    <StackPanel Orientation="Vertical">
        <TextBlock Text="{x:Bind MyProperty}" FontSize="24"/>
        <Button Content="Click Me" Click="Button_Click"/>
    </StackPanel>
</Window>
Code language: HTML, XML (xml)

Click=”Button_Click” 안의 Button_Click 텍스트에 커서를 올리고 키보드 F12를 누르면 .h, .cpp 파일에 이벤트 함수가 자동 생성됩니다.

void Button_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);

작성 방식은 앞선 예시와 동일합니다. 다음으로 클릭 횟수를 저장할 int32_t 타입의 비공개 멤버 변수를 선언합니다.

먼저 MainWindow.xaml.h 헤더 파일에 카운트 값을 저장할 정수 속성을 추가합니다.

.idl 파일에 작성한 속성은 외부 접근용 인터페이스일 뿐 실제 데이터를 저장하는 필드는 직접 선언해야 합니다.

IDL에 Int32 MyProperty를 작성하면 클래스 외부에 읽기/쓰기 가능한 Int32 속성이 노출됩니다.

컴파일러가 자동으로 Get/Set 가상 함수와 속성 변경 이벤트 MyPropertyChanged를 생성합니다.

int32_t m_myPropValue = 0; // 비공개 변수, 클릭 횟수 저장!Code language: C++ (cpp)
#pragma once

#include "MainWindow.g.h"

namespace winrt::WinuiDemo::implementation
{
    struct MainWindow : MainWindowT<MainWindow>
    {
    private:
        int32_t m_myPropValue = 0; // MyProperty 값 저장

    public:
        MainWindow()
        {
            // Xaml 객체는 생성자 내에서 InitializeComponent를 호출하면 안 됩니다.
            // 참고: https://github.com/microsoft/cppwinrt/tree/master/nuget#initializecomponent
        }

		
		//getter & setter 함수
        int32_t MyProperty();
        void MyProperty(int32_t value);

        //클릭 이벤트 함수
        void Button_Click(winrt::Windows::Foundation::IInspectable const& sender, winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e);
    };
}

namespace winrt::WinuiDemo::factory_implementation
{
    struct MainWindow : MainWindowT<MainWindow, implementation::MainWindow>
    {
    };
}


Code language: C++ (cpp)

이제 .cpp 파일의 속성 읽기/쓰기 함수를 수정합니다. 클릭 이벤트 안에서 MyProperty()로 현재 값을 가져온 뒤 1을 더해 다시 할당합니다. 가장 중요한 한 가지가 있습니다.

this->Bindings->Update(); 이 코드는 절대 빼먹으면 안 됩니다. 이 코드가 해당 속성에 바인딩된 모든 UI 요소에 새로고침을 알려주며, 누락하면 화면 값이 갱신되지 않습니다.

#include "pch.h"
#include "MainWindow.xaml.h"
#if __has_include("MainWindow.g.cpp")
#include "MainWindow.g.cpp"
#endif

using namespace winrt;
using namespace Microsoft::UI::Xaml;

// WinUI, WinUI 프로젝트 구조 및 템플릿에 대한 자세한 정보: http://aka.ms/winui-project-info.

namespace winrt::WinuiDemo::implementation
{
    int32_t MainWindow::MyProperty()
    {
        return m_myPropValue; //m_myPropValue 값 반환
    }

    void MainWindow::MyProperty(int32_t  value)
    {
        m_myPropValue = value; //m_myPropValue에 값 저장
        this->Bindings->Update(); // 페이지 내 모든 x:Bind 바인딩 강제 갱신, UI 표시 업데이트
    }
}

void winrt::WinuiDemo::implementation::MainWindow::Button_Click(winrt::Windows::Foundation::IInspectable const& sender,
 winrt::Microsoft::UI::Xaml::RoutedEventArgs const& e)
{
    MyProperty(MyProperty() + 1);//m_myPropValue 값 갱신, 1 증가
}
Code language: C++ (cpp)

다시 빌드하고 실행합니다.

저자의 환경에서는 빌드 대기 시간이 매우 길었으며 PC 사양에 따라 차이가 발생합니다.

Build started at 15:29...
1>------ Build started: Project: WinuiDemo, Configuration: Debug x64 ------
1>WindowsAppSDKMLDeploymentMode=Framework
1>App.xaml.cpp
1>MainWindow.xaml.cpp

C++ 빌드 과정에서 수많은 중간 파일이 생성되며 저자 환경에서는 10분 이상 빌드가 완료되지 않았습니다.

로컬 시간 15:40에 드디어 빌드가 완료되고 앱 창이 표시되었으며 총 11분이 소요되었습니다. 중간에 프로그램이 멈춘 줄 알고 Visual Studio를 닫을 뻔했습니다.

최종 실행 결과

이번 수업은 여기까지입니다. 오늘 배운 내용은 두 가지입니다. 첫째, 버튼 클릭 후 백엔드 로직을 실행하고 화면 내용을 수정하는 방법, 둘째, 속성 바인딩으로 백엔드 값을 변경하면 UI가 자동으로 최신 상태로 갱신되는 원리입니다.

답글 남기기

이메일 주소는 공개되지 않습니다. 필수 필드는 *로 표시됩니다