1️⃣ 학습 목표

: 예제의 학습 목표와 동작 시나리오를 파악한 뒤, 소스코드를 직접 확인합니다.

더보기

✔️ 1. 학습 목표

  • Step 1. 
    • CommunityToolkit.Mvvm 패키지를 통한 자동완성 기능을 학습하기에 앞서,
      전통적인 방식의 C# MVVM 패턴 구현 방법을 되짚어 봅니다.
    • INotifyPropertyChanged 인터페이스를 상속 구현하여,
      프로퍼티가 변경되었을 때, View에 반영되는 로직을 구현하는 방법을 되짚어봅니다.
  • Step 2.
    • 이후에 CommunityToolkit.Mvvm 패키지를 사용해 자동 구현할 때,
      어떤 부분이 자동화되어 편리한지 확인합니다.
  • Step 3.
    • 그리고 프로젝트의 어느 부분에 적용하면 효과적일지 예상해봅니다.

 

 

 

 

✔️ 2. 예제 동작 시나리오

  1. TextBox에 문자열을 입력하면
  2. TextBlock에 반영되어 동시에 출력됩니다.

 

2️⃣ INotifyPropertyChanged - 동작 구조

: MVVM 구조에서 View의 동작과 ViewModel Property와 연결을 구현하는 방법입니다.

더보기

ViewModel 네임스페이스를 View에 등록합니다. DataContext를 지정합니다.

 

View에서 입력받은 데이터가 바인딩 된 ViewModel의 Name 프로퍼티의 Setter 실행 후

name 필드 값으로 할당됩니다.

 

ViewModel의 Name 프로퍼티의 Setter 로직 내부의 OnPropertyChanged 메서드가 동작하면,

PropertyChanged 이벤트를 발생시킵니다.

 

WPF 바인딩 엔진이 PropertyChanged 이벤트를 감지하면 

Name 프로퍼티와 바인딩된 View의 컨트롤에 업데이트를 요청합니다.

//이벤트 구독자(View → WPF 바인딩 엔진)가 이 이벤트를 수신
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName))

 

업데이트 요청을 동작하기 위해 ViewModel의 Name 프로퍼티 Getter를 통해

View 바인딩된 컨트롤에 반영됩니다.



3️⃣  PropertyChanged?.Invoke(...) - 동작 구조

: 개발자가 별도로 이벤트 핸들러를 등록하지 않아도, WPF 바인딩 엔진이 내부적으로 리스너 역할을 합니다.

더보기
protected virtual void OnPropertyChanged(string propertyName)
{
    PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}

PropertyChanged는 이벤트(event)입니다.
PropertyChanged?.Invoke(...)는 이벤트에 연결된 모든 이벤트 핸들러(delegate)를 호출합니다.

 


단계  설명
PropertyChanged 이벤트에 등록된 구독자(delegate) 목록 확인
이벤트에 구독자가 있으면? → 각 delegate를 순서대로 호출
delegate의 메서드 시그니처는 PropertyChangedEventHandler 형태
각 delegate는 (object sender, PropertyChangedEventArgs e) 파라미터를 전달받음
➡️ 개발자가 별도로 이벤트 핸들러를 등록하지 않아도, WPF 바인딩 엔진이 내부적으로 리스너 역할을 함
WPF의 바인딩 엔진(리스너로 등록되어 있음)이 이 이벤트를 수신함
바인딩 엔진이 어떤 속성이 변경되었는지(e.PropertyName) 확인
해당 속성을 바인딩한 View 요소(UI 컨트롤)를 찾아 값 업데이트 요청
View(UI)가 최신 값을 반영 (예: TextBlock.Text 갱신)

 

4️⃣ Ex01INotifyPropertyChanged

: 간단한 프로젝트를 INotifyPropertyChanged 인터페이스를 직접 상속받아 자동완성 없이, 전통적인 방식으로 단계별로 구현해봅니다.

더보기

📁 1. 가장먼저, 아래 링크를 참고해 WPF 프로젝트를 생성 합니다.

 

WPF 프로젝트 생성하기

01. Visual Studio 실행더보기 02. 새 프로젝트 생성더보기❶ 최근 실행한 프로젝트의 목록을 보여줍니다.❷ GitHub, Azure, DevOps, Bitbucket 등 원격 저장소에서 프로젝트를 가져옵니다.❸ 내 컴퓨터의 로컬

basiclike.tistory.com

 

 

📁 2. 생성한 WPF 프로젝트에, 아래 링크를 참고해 CommunityToolkit.Mvvm 패키지를 설치합니다.

 

1.2 패키지 설치 방법

1️⃣ "NuGet 패키지 관리자"에서, CommunityToolkit.Mvvm 설치하는 방법더보기 WPF 프로젝트 생성하기01. Visual Studio 실행더보기 02. 새 프로젝트 생성더보기❶ 최근 실행한 프로젝트의 목록을 보여줍니다.

basiclike.tistory.com

 

 

📁 3. 프로젝트 구조

Ch01_Sec03_Ex01SourceGenerator/
├── ViewModels/
│   ├── MainViewModel.cs         ← 메인 뷰모델     
├── Views/
│   ├── MainWindow.xaml          ← 메인 뷰
│   └── MainWindow.xaml.cs
├── App.xaml
└── App.xaml.cs

 

 

📁 4. ViewModel 클래스 만들기

ViewModels 폴더에, MainViewModel.cs를 생성하고

아래 소스코드를 붙여넣으면, 관련 라이브러리가 자동 참조됩니다.

using System;
using System.ComponentModel;
using System.Collections.Generic;

/// <summary>
/// MainViewModel 클래스는 MVVM 패턴에서 ViewModel 역할을 수행합니다.
/// ViewModel은 UI(View)와 데이터(Model) 사이에서 데이터 바인딩을 중계하는 역할을 합니다.
/// </summary>
public class MainViewModel : INotifyPropertyChanged
{
    // 실제 데이터를 저장하는 private 필드
    // ViewModel의 속성(Property)은 이 필드를 기반으로 동작합니다.
    private string? name;

    /// <summary>
    /// Name 속성은 View(XAML UI)와 데이터 바인딩됩니다.
    /// 사용자가 TextBox에 값을 입력하면, 이 속성의 setter가 호출됩니다.
    /// setter 내부에서 값이 실제로 변경되면 OnPropertyChanged를 호출하여 UI에 변경 사실을 알립니다.
    /// </summary>
    public string Name
    {
        // name 필드의 값을 반환하되, null일 경우 빈 문자열로 처리
        get => name ?? string.Empty;

        // 값 설정 시, 기존 값과 다르면 변경 및 변경 알림 호출
        set
        {
            // 값이 이전 값과 다를 경우에만 변경 처리 (불필요한 이벤트 방지)
            if (!EqualityComparer<string>.Default.Equals(name, value))
            {
                name = value;

                // UI(View) 측에 "Name" 속성이 변경되었음을 알림
                OnPropertyChanged(nameof(Name));
            }
        }
    }

    /// <summary>
    /// INotifyPropertyChanged 인터페이스의 이벤트입니다.
    /// 속성 값이 변경되면 이 이벤트를 발생시켜, 바인딩된 UI가 자동으로 업데이트됩니다.
    /// </summary>
    public event PropertyChangedEventHandler? PropertyChanged;

    /// <summary>
    /// 속성 변경을 UI에 알리기 위한 메서드입니다.
    /// PropertyChanged 이벤트를 통해 바인딩된 컨트롤에 변경 사실을 전달합니다.
    /// </summary>
    /// <param name="propertyName">변경된 속성의 이름 (예: "Name")</param>
    protected virtual void OnPropertyChanged(string propertyName)
    {
        // 이벤트 구독자가 있을 경우에만 호출하여 성능 최적화
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

 

 

📁 5. View 구성하기

Views 폴더 아래에, MainWindow.xaml을 이동시킵니다.(또는 새로운 MainView를 생성합니다.)

아래 XAML 코드를 붙여넣고, xmlns를 본인 프로젝트의 ViewModel 경로로 지정합니다.

<!-- MainWindow.xaml -->
<Window x:Class="WpfMvvmToolkit03_INotifyPropertyChanged.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        
        <!-- ViewModel 클래스가 위치한 네임스페이스 참조 -->
        xmlns:vm="clr-namespace:WpfMvvmToolkit03_INotifyPropertyChanged.ViewModel"

        Title="INotifyPropertyChanged Demo" Height="200" Width="400">

    <!-- View의 DataContext를 MainViewModel로 설정 -->
    <!-- 이렇게 하면 View에서 ViewModel의 속성에 바인딩할 수 있게 됩니다 -->
    <Window.DataContext>
        <vm:MainViewModel />
    </Window.DataContext>

    <StackPanel Margin="20">
        
        <!-- TextBox: 사용자가 입력하는 UI 요소 -->
        <!-- Name 속성과 양방향 바인딩되어, 텍스트를 입력하면 ViewModel.Name이 자동 갱신됩니다 -->
        <!-- UpdateSourceTrigger=PropertyChanged: 사용자가 입력할 때마다 즉시 ViewModel에 반영 -->
        <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" 
                 FontSize="14" Margin="0,0,0,10"/>

        <!-- TextBlock: 바인딩된 ViewModel.Name 값을 실시간으로 표시 -->
        <!-- ViewModel에서 Name 값이 변경되면, TextBlock에도 자동으로 반영됩니다 -->
        <TextBlock Text="{Binding Name}" FontSize="20" FontWeight="Bold"/>

    </StackPanel>
</Window>

 



📁6. App 수정

App.Xaml 에서 시작 View 경로를, ViewModel 폴더로 이동시킨 MainWindow로 변경합니다.