1️⃣ Source Generator 개요

더보기

📚 Microsoft Docs: Microsoft Learn / Learn / .NET / MVVM

 

 

소스 생성기(SG, Source Generator)란?

소스 생성기는 .NET 5부터 도입된 기능으로, 우리가 반복적으로 작성하던 MVVM 관련 C# 코드를 컴파일 타임에 자동으로 생성하여 프로젝트에 생성해주는 컴파일러 확장 도구 입니다.

 

 

사용 방법

개발자가 클래스에 partial 키워드와 특정 어트리뷰트[attribute]를 붙이면,
프로젝트가 빌드될 때 필요한 코드를 자동으로 생성합니다.

 

 

 

 

 

2️⃣ 단순 소스코드 비교 (기본 C# MVVM 구현 VS Source Generator )

더보기

*단순히 소스코드의 양 자체만 비교해봅니다.

 

✔️ 1. 순수 C#으로 INotifyPropertyChangedICommand를 직접 구현

// 기본 C#으로 INotifyPropertyChanged 상속받아 MVVM 구현
public class MainViewModel : INotifyPropertyChanged
{
private string userName;
public string UserName
{
get => userName;
set
{
if (userName != value)
{
userName = value;
OnPropertyChanged(); // nameof(UserName) 자동 전달
}
}
}
public ICommand SayHelloCommand { get; }
public MainViewModel()
{
SayHelloCommand = new RelayCommand(SayHello);
}
private void SayHello()
{
Console.WriteLine($"안녕하세요, {UserName}님!");
}
public event PropertyChangedEventHandler? PropertyChanged;
protected void OnPropertyChanged([CallerMemberName] string? propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
// 간단한 ICommand 구현
public class RelayCommand : ICommand
{
private readonly Action execute;
private readonly Func<bool>? canExecute;
public RelayCommand(Action execute, Func<bool>? canExecute = null)
{
this.execute = execute;
this.canExecute = canExecute;
}
public event EventHandler? CanExecuteChanged;
public bool CanExecute(object? parameter) => canExecute?.Invoke() ?? true;
public void Execute(object? parameter) => execute();
public void RaiseCanExecuteChanged() => CanExecuteChanged?.Invoke(this, EventArgs.Empty);
}

 

 

✔️ 2. SG(Source Generator) 사용

public partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private string userName;
[RelayCommand]
private void SayHello()
{
Console.WriteLine($"Hello, {UserName}");
}
}

*수동으로 구현하면 수십 줄인데, source generator를 쓰면 1~2줄로 해결됩니다.

 

 

 

 

 

3️⃣ Source Generator 자동완성 구조 살펴보기 - (1) ObservableProperty

더보기

*CommunityToolkit.Mvvm 패키지 설치 후 진행해주세요.

 

✔️ 1. ObservableProperty 사용해보기

프로젝트를 생성하고, 폴더 하나를 만든 뒤, 테스트용 클래스 파일을만들어 줍니다.

 

필드(userName) 하나를 생성하고, [ObservableProperty] 어트리뷰트를 추가하면,

관련 패키지의 네임스페이스가 자동 추가됩니다.

 

ViewModel 클래스에 ObservableObject 를 상속받고, 클래스는 partial 로 변경한 뒤,   빌드합니다.

 

 

 

 

✔️ 2. Source Generator가 자동 생성한 구현부 살펴보기

CommunityToolkit.Mvvm 패키지의 Source Generator는 MVVM에 필요한 소스코드를 자동 완성해줍니다.

솔루션 탐색기에서, 자동완성된 On___Changed 함수를 더블 클릭합니다.

 

테스트용 ViewModel 클래스 파일의 partial 클래스에, 자동완성된 MVVM 코드들을 확인 할 수 있습니다.

 

 

 

 


4️⃣ Source Generator 자동완성 구조 살펴보기 - (2) RelayCommand

더보기

✔️ 1. RelayCommand 사용해보기

 프로젝트를 생성하고, 폴더 하나를 만든 뒤, 테스트용 클래스 파일을만들어 줍니다.

 

메서드 SayHello( )를 생성하고, ③ [RelayCommand] 어트리뷰트를 추가하면, 

 관련 패키지의 네임스페이스가 자동 추가됩니다.

 

⑤ ObservableObject 를 상속받고, ⑥ 클래스는 partial 로 변경한 뒤,  빌드합니다.

 

 

 

 

✔️ 2. Source Generator자동 생성한 구현부 살펴보기

 CommunityToolkit.Mvvm 패키지의 Source Generator는  MVVM에 필요한 소스코드를 자동 완성해줍니다.

 솔루션 탐색기에서, 자동완성된 ___Command 함수를 더블 클릭합니다.

 

 테스트용 클래스 파일의 partial 클래스에, 자동완성된 코드를 확인 할 수 있습니다.

 

 

 

 


5️⃣ Attribute [어트리뷰트]

더보기

*Attribute를 '특성'이라는 한국어로 사용하면, 혼동될 상황이 많다.

 

✔️ 사용 문법

[AttributeName]
[AttributeName(parameter1, parameter2, ...)]

※  [RelayCommand]는 실제로 RelayCommandAttribute 입니다. Attribute로 끝나지만, 사용할 땐 생략 가능합니다.

 

 

✔️ 예제 기반 사용법 설명

[ObservableProperty]
private string userName;
  • 이 필드는 자동으로 public string UserName 프로퍼티로 구현되고
  • PropertyChanged 이벤트도 함께 발생시키는 코드가 컴파일 시 자동 생성됩니다.

 

[RelayCommand]
private void ShowGreeting()
  • ShowGreetingCommand라는 ICommand 속성을 자동으로 만들어서 XAML에서 사용할 수 있게 해줍니다.

 

 

✔️ 핵심 요약

 

[ ] 안에 사용된 것은 Attribute(특성)이며,

컴파일러나 도구에게 특별한 의미나 동작을 지정하는 메타데이터입니다.

 

CommunityToolkit.Mvvm 패키지는 어트리뷰트를 활용해 MVVM 코드를 간결하게 자동 생성하게 도와줍니다.

 

 

 

 

 

6️⃣ partial 키워드를 사용하는 이유

더보기
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Windows;
namespace WpfApp.ViewModels
{
// partial 키워드를 사용하는 이유:
// Source Generator가 자동으로 생성하는 코드(예: UserName 속성, ShowGreetingCommand 명령)를
// 동일 클래스 이름의 다른 partial 파일로 분리하여 추가할 수 있게 해줌
// 즉, 수동 작성 코드와 자동 생성 코드를 분리하여 관리 가능하게 함
namespace WPF_ToolKit01.ViewModel
{
internal partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private string? userName;
[RelayCommand]
private void ShowGreeting()
{
MessageBox.Show($"Hello, {UserName}!");
}
}
}

 

 

 

 

 

 

7️⃣ 예제

더보기

✔️ 1. 동작 시나리오

  1. 텍스트 박스에 이름 입력
  2. 버튼 클릭
  3. 메시지 박스에 "Hello, {입력한 이름}!" 출력

 

 

✔️ 2. CommunityToolkit.Mvvm 으로 구현

 

📁 2.1 프로젝트 구조

02_WpfMvvmToolkit_Eg01/
├── ViewModels/
│ ├── MainViewModel.cs
└── Views/
├── MainWindow.xaml ← 메인 뷰
└── MainWindow.xaml.cs

 

 

📁 2.2 ViewModel 클래스 만들기

using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using System.Windows;
internal partial class MainViewModel : ObservableObject
{
[ObservableProperty]
private string? userName;
[RelayCommand]
private void ShowGreeting()
{
MessageBox.Show($"Hello, {UserName}!");
}
}

 

 

📁 2.3 XAML 화면 구성

 

xmlns:vm="clr-namespace:WPF_ToolKit01.ViewModel"
Title="Toolkit.MVVM Example" Height="200" Width="300">
<Window.DataContext>
<vm:MainViewModel />
</Window.DataContext>
<StackPanel Margin="20">
<TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" />
<Button Content="Greet"
Command="{Binding ShowGreetingCommand}"
Margin="0,10,0,0"/>
</StackPanel>

 

 

✔️ 3. 소스코드

 

WpfMvvmToolkit02.zip
0.07MB

 

 

 

 

 

8️⃣ 예제 - 상세 주석

더보기

✔️ ViewModel 클래스 상세 주석

using CommunityToolkit.Mvvm.ComponentModel; // MVVM에서 속성 변경 알림(INotifyPropertyChanged)을 지원하는 기본 클래스 제공
using CommunityToolkit.Mvvm.Input; // ICommand 구현을 쉽게 하기 위한 특성(Attribute) 지원
using System.Windows; // WPF의 기본 UI 요소(MessageBox 등) 사용을 위해 필요
// ViewModel 클래스는 ObservableObject를 상속하여 속성 변경 알림 기능을 자동으로 제공
// partial 키워드를 사용하는 이유:
// - Source Generator가 자동으로 생성하는 코드(예: UserName 속성, ShowGreetingCommand 명령)를
// - 동일 클래스 이름의 다른 partial 파일로 분리하여 추가할 수 있게 해줌
// - 즉, 수동 작성 코드와 자동 생성 코드를 분리하여 관리 가능하게 함
public partial class MainViewModel : ObservableObject
{
// [ObservableProperty]는 다음과 같은 코드를 자동 생성해줌:
// public string UserName
// {
// get => userName;
// set => SetProperty(ref userName, value);
// }
// 또한, 속성 변경 시 INotifyPropertyChanged 이벤트를 발생시킴
[ObservableProperty]
private string userName; // 사용자 이름을 저장할 속성 (자동으로 UserName 속성 생성됨)
// [RelayCommand]는 다음과 같은 코드를 자동 생성해줌:
// public ICommand ShowGreetingCommand => new RelayCommand(ShowGreeting);
// 즉, 이 메서드를 바탕으로 ICommand를 구현한 명령 속성이 자동 생성됨
// 이 명령은 XAML에서 버튼 클릭과 같은 이벤트에 바인딩할 수 있음
[RelayCommand]
private void ShowGreeting()
{
// 사용자 이름을 포함한 환영 메시지를 MessageBox로 표시
MessageBox.Show($"Hello, {UserName}!");
}
}

 

어트리뷰트와 자동 구현된 기능:

  • [ObservableProperty]: INotifyPropertyChanged 자동 생성
  • [RelayCommand]: ICommand 구현부 자동 생성

 

✅ 자동 생성되는 것:

  • UserName 속성 + OnPropertyChanged 호출
  • ShowGreetingCommand 명령 생성 (사용자 정의한 ShowGreeting에 의해)

 

 요약

기능 설명
[ObservableProperty] 필드 → 속성 자동 생성 + 변경 알림
[RelayCommand] 메서드 → ICommand 구현 자동 생성
ViewModel은 ObservableObject를 상속 MVVM 패턴의 핵심 기능을 제공

 

 

✔️ XAML 화면 구성

<!-- 태그(< >꺽쇠기호 내부)안에는 아래 주석 추가가 불가능합니다. -->
<!-- WPF 기본 UI 요소를 위한 XML 네임스페이스 -->
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
<!-- 디자인 타임 지원 (Blend 등에서 사용) -->
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
<!-- 현재 프로젝트의 기본 네임스페이스 -->
xmlns:local="clr-namespace:WpfApp"
<!-- ViewModel 클래스가 위치한 네임스페이스 -->
xmlns:vm="clr-namespace:WpfApp.ViewModels"
<!-- 윈도우 제목 및 크기 설정 -->
Title="Toolkit.MVVM Example" Height="200" Width="300">
<Window.DataContext>
<vm:MainViewModel />
<!-- ViewModel 인스턴스를 XAML의 DataContext로 설정 -->
</Window.DataContext>
<StackPanel Margin="20">
<!-- 수직 방향으로 자식 요소를 배치하는 레이아웃 컨트롤 -->
<!-- TextBox는 ViewModel의 UserName 속성과 양방향 바인딩됨 -->
<!-- UpdateSourceTrigger=PropertyChanged : 텍스트가 바뀔 때마다 즉시 ViewModel로 전달 -->
<TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" />
<!-- Button 클릭 시 ViewModel의 ShowGreetingCommand 명령을 실행 -->
<!-- Margin="0,10,0,0"은 위쪽 여백을 줘서 간격 확보 -->
<Button Content="인사" Command="{Binding ShowGreetingCommand}" Margin="0,10,0,0"/>
</StackPanel>
</Window>