RelayCommand는 MVVM 구조에서 메서드(Logic)를 실행하는 방법입니다.
Relay(중계자) = 바통을 넘기다, 전달하다 → "동작(명령)을 전달(delegate)하는 역할"
(View)Command → RelayCommand → (ViewModel)Method

 

1️⃣ RelayCommand 개요

더보기

📚 Microsoft Docs: CommunityToolkit.Mvvm.Input.RelayCommand

 

 

작동 방식

 

CommunityToolkit.Mvvm.Input.RelayCommand의 [RelayCommand] 어트리뷰트
ICommand 인터페이스를 자동으로 구현해주는 소스 생성기(SG) 기반 기능입니다.


[RelayCommand] 어트피뷰트를 메서드에 붙이면 

해당 메서드를 실행하는 <메서드이름>Command 속성이 자동으로 생성됩니다.

UI에서 ViewModel의 메서드를 실행하도록 연결하는 복잡한 ICommand 구현을 자동으로 대체할 수 있습니다.

 

 

예제 소스코드

WpfMvvmToolkit.zip
0.27MB

 

2️⃣ 01ICommand - 자동완성 없이, C# MVVM 구현 구조 예제 

더보기

✔️ 1. 학습 목표

 

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

 

 

 

 

✔️ 2. 동작 시나리오

  1. 사용자가 이름을 입력할 수 있는 TextBox에 이름을 입력한다.
  2. View의 "인사하기" 버튼을 눌렀을 때, ViewModel 메서드가 동작하고
  3. Hello, [이름]! 메시지를 하단의 TextBlock에 출력합니다.
  4. *이름이 비어 있으면 인사하지 않고 "이름을 입력하세요!" 라고 안내한다.

 

 

 

 

✔️ 3. 자동완성 없이, 전통적인 방식으로  C# MVVM 구조를 만들기 위해 ICommand  구현

 

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

 

WPF 프로젝트 생성하기

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

basiclike.tistory.com

 

 

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

 

02. 패키지 설치 방법

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

basiclike.tistory.com

 

 

📁 3.3 프로젝트 구조

WpfMvvmToolkit05_01ICommand/
├── Commands/
│   └── RelayCommand.cs
├── ViewModels/
│   └── MainViewModel.cs         
└── Views/
    └── MainWindow.xaml          ← 메인 뷰
    └── MainWindow.xaml.cs

 


📁 3.4 ICommand 동작 구조

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

 

View에서 버튼을 클릭하면 바인딩 된 RelayCommand가 실행됩니다.

RelayCommand는, MainViewModel 생성시  SayHello() 메서드가 등록되도록 구현되어 있습니다.

RelayCommand가 실행되면, 등록된 S ayHello() 메서드가 동작합니다.

 

 

📁 3.5 ICommand 구현

// ICommand를 간단하게 구현한 RelayCommand 클래스 (매개변수 없는 Action 지원)
public class RelayCommand : ICommand
{
    private readonly Action _execute;

    public RelayCommand(Action execute)
    {
        _execute = execute;
    }

    // 항상 true를 반환하여 버튼을 항상 활성 상태로 유지
    public bool CanExecute(object? parameter) => true;

    // 버튼 클릭 시 실행될 메서드 호출
    public void Execute(object? parameter) => _execute.Invoke();

    // CanExecuteChanged 이벤트 (사용되지 않음)
    public event EventHandler? CanExecuteChanged;
}

 


📁 3.6 ViewModel 구현하기

// CommandParameter 없이, 단순히 ViewModel 속성으로 동작하는 예제
public class MainViewModel : INotifyPropertyChanged
{
    private string? name;
    private string? greetingMessage;

    // 사용자 입력을 저장하는 속성
    public string? Name
    {
        get => name;
        set
        {
            if (name != value)
            {
                name = value;
                OnPropertyChanged(); // UI에 알림
            }
        }
    }

    // 인사 메시지를 저장하는 속성
    public string? GreetingMessage
    {
        get => greetingMessage;
        set
        {
            if (greetingMessage != value)
            {
                greetingMessage = value;
                OnPropertyChanged(); // UI에 알림
            }
        }
    }

    // ICommand 타입의 커맨드 속성. 버튼 클릭 시 실행됨
    public ICommand SayHelloCommand { get; }

    public MainViewModel()
    {
        // CommandParameter 없이 ViewModel 속성을 참조하는 방식
        SayHelloCommand = new RelayCommand(SayHello);
    }

    // 커맨드로 실행될 메서드
    private void SayHello()
    {
        if (!string.IsNullOrWhiteSpace(Name))
            GreetingMessage = $"안녕하세요, {Name}님!";
        else
            GreetingMessage = "이름을 입력하세요!";
    }

    public event PropertyChangedEventHandler? PropertyChanged;

    protected void OnPropertyChanged([CallerMemberName] string propertyName = null!)
    {
        PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
    }
}

 

 

📁 3.7 View 구성하기

    xmlns:vm="clr-namespace:WpfMvvmToolkit05_01ICommand.ViewModels"
    Title="RelayCommand Demo" Height="200" Width="300">

<Window.DataContext>
    <vm:MainViewModel />
</Window.DataContext>

<StackPanel Margin="20">
    <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"  
             Margin="0,0,0,10"/>

    <Button Content="인사하기" 
            Command="{Binding SayHelloCommand}" 
            Margin="0,0,0,10"/>

    <TextBlock Text="{Binding GreetingMessage}" 
               FontWeight="Bold" />
</StackPanel>

 


 

3️⃣ 02RelayCommand - CommunityToolkit.Mvvm 패키지 사용 구조 예제

더보기

✔️ 1. 학습 목표

  • "01ICommand - 기본 C# MVVM 구현 구조 예제" 와 비교하여
    CommunityToolkit.Mvvm 패키지를 사용할 때, 어떤 부분을 효과적으로 사용할 수 있는지 확인합니다.
// MainViewModel 클래스는 MVVM 패턴에서 View와 Model 사이의 중간 역할을 담당합니다.
// ObservableObject를 상속받음으로써 INotifyPropertyChanged를 자동으로 구현합니다.
public partial class MainViewModel : ObservableObject
{
    // [RelayCommand] 특성을 메서드에 붙이면 내부적으로 SayHelloCommand라는 ICommand 속성이 자동으로 생성됩니다.
    // 이 명령은 XAML에서 Button의 Command 속성과 연결되어 버튼 클릭 시 이 메서드가 실행되도록 합니다.
    // 예: <Button Command="{Binding SayHelloCommand}" />
    [RelayCommand]
    private void SayHello()
    {
        // Name 속성이 비어 있거나 공백일 경우 안내 메시지를 출력하고
        // 값이 있을 경우 인사 메시지를 GreetingMessage 속성에 저장합니다.
        if (string.IsNullOrWhiteSpace(Name))
        {
            GreetingMessage = "이름을 입력하세요!";
        }
        else
        {
            GreetingMessage = $"안녕하세요, {Name}님!";
        }

        // GreetingMessage 속성 값이 변경되면 PropertyChanged 이벤트가 발생하며,
        // 이 속성을 바인딩한 TextBlock의 UI 내용도 자동으로 업데이트됩니다.
    }
}

 

 

 

✔️ 2. CommunityToolkit.Mvvm 패키지의 [RelayCommand] 사용해 보기


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

 

WPF 프로젝트 생성하기

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

basiclike.tistory.com

 

 

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

 

02. 패키지 설치 방법

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

basiclike.tistory.com

 

 

📁 2.3 ViewModel 구현하기

 기존 ViewModel 파일에

메시지 박스에 입력받은 name 프로퍼티 값을 greetingMessage 프로퍼티에 추가하는 로직을 구현하고

③ 메서드 상단에 [RelayCommand] 어트리뷰트를 추가하면, 

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

 

⑤ ViewModel 클래스에 ObservableObject를 상속받고,

⑥ 클래스는 public partial로 변경되었는지 확인하고

 빌드합니다.

 

public partial class MainViewModel : ObservableObject
{
    [ObservableProperty]
    private string? name;

    [ObservableProperty]
    private string? greetingMessage;

    [RelayCommand]
    private void SayHello()
    {
        if (!string.IsNullOrWhiteSpace(Name))
            GreetingMessage = $"안녕하세요, {Name}님!";
        else
            GreetingMessage = "이름을 입력하세요!";
    }
}

 

✔️ 2.3  XAML 화면 구성 (동일)

        xmlns:vm="clr-namespace:WPF_ToolKit04_03.ViewModel"
        Title="RelayCommand Demo" Height="200" Width="300">

    <Window.DataContext>
        <vm:MainViewModel />
    </Window.DataContext>

    <StackPanel Margin="20">
        <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}"  Margin="0,0,0,10"/>

        <Button Content="인사하기" Command="{Binding SayHelloCommand}" Margin="0,0,0,10"/>

        <TextBlock Text="{Binding GreetingMessage}" FontWeight="Bold" />
    </StackPanel>

 

 

✔️ 3. 동작 구조

 

  • 실행 흐름
    • 버튼 클릭 → XAML Command RelayCommand ViewModel Method 실행
  • ViewModel
    • [RelayCommand] 어트리뷰트를 붙이면 SayHelloCommand가 자동으로 생성됨
  • View
    • Command="{Binding SayHelloCommand}"를 통해 버튼과 연결됨
    • 입력 필드와 Name 속성은 양방향 바인딩

 

4️⃣  Source Generator가 자동 생성한 구현부 살펴보기

더보기

 CommunityToolkit.Mvvm 패키지의 Source Generator는 

 MVVM에 필요한 소스코드를 자동 완성해 줍니다.

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

 

 테스트용 ViewModel 클래스 파일의 partial 클래스에서

④ 자동완성된 MVVM 소스코드들을 확인할 수 있습니다.

CommunityToolkit.Mvvm 패키지의 Source Generator가 자동구현하지 않았다면, 개발자가 수동으로 구현해야 하는 부분입니다


 

5️⃣ RelayCommand ] 구현 - 상세 주석

더보기

🔍 ViewModel 클래스 만들기 (MainViewModel.cs)

// MainViewModel 클래스는 MVVM 패턴에서 View와 Model 사이의 중간 역할을 담당합니다.
// ObservableObject를 상속받음으로써 INotifyPropertyChanged를 자동으로 구현합니다.
public partial class MainViewModel : ObservableObject
{
    // 사용자로부터 입력받은 이름을 저장하는 속성입니다.
    // [ObservableProperty] 특성을 사용하면 name 필드에 대한 Name 속성이 자동 생성되고,
    // 속성이 변경될 때 UI에 자동으로 통지됩니다 (PropertyChanged 이벤트 발생).
    [ObservableProperty]
    private string? name;

    // 인사 메시지를 화면에 표시하기 위한 속성입니다.
    // GreetingMessage 속성은 TextBlock에 바인ㅁ
    private string? greetingMessage;

    // [RelayCommand] 특성을 메서드에 붙이면 내부적으로 SayHelloCommand라는 ICommand 속성이 자동으로 생성됩니다.
    // 이 명령은 XAML에서 Button의 Command 속성과 연결되어 버튼 클릭 시 이 메서드가 실행되도록 합니다.
    // 예: <Button Command="{Binding SayHelloCommand}" />
    [RelayCommand]
    private void SayHello()
    {
        // Name 속성이 비어 있거나 공백일 경우 안내 메시지를 출력하고
        // 값이 있을 경우 인사 메시지를 GreetingMessage 속성에 저장합니다.
        if (string.IsNullOrWhiteSpace(Name))
        {
            GreetingMessage = "이름을 입력하세요!";
        }
        else
        {
            GreetingMessage = $"안녕하세요, {Name}님!";
        }

        // GreetingMessage 속성 값이 변경되면 PropertyChanged 이벤트가 발생하며,
        // 이 속성을 바인딩한 TextBlock의 UI 내용도 자동으로 업데이트됩니다.
    }
}

 

🔍 XAML 화면 구성

<!--
    이 XAML 파일은 MVVM 패턴을 따르는 WPF 애플리케이션의 MainWindow입니다.
    ViewModel(MainViewModel)과의 바인딩을 통해 사용자 입력을 처리하고 결과를 화면에 표시합니다.
-->
<Window x:Class="StudentRelayCommandApp.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:vm="clr-namespace:StudentRelayCommandApp.ViewModels"
        Title="RelayCommand 실습" Height="200" Width="300">

    <!-- ViewModel(MainViewModel)을 이 View의 DataContext로 설정합니다.
         이렇게 하면 ViewModel의 속성과 명령을 이 XAML에서 직접 바인딩할 수 있습니다. -->
    <Window.DataContext>
        <vm:MainViewModel />
    </Window.DataContext>

    <!-- StackPanel은 요소를 수직으로 정렬하는 레이아웃 컨트롤입니다. -->
    <StackPanel Margin="20">

        <!--
            TextBox는 사용자로부터 이름을 입력받는 UI 요소입니다.
            Text 속성을 ViewModel의 Name 속성과 바인딩합니다.
            UpdateSourceTrigger=PropertyChanged 설정을 통해 텍스트가 변경될 때마다 ViewModel에 즉시 반영됩니다.
        -->
        <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" 
                 PlaceholderText="이름 입력" Margin="0,0,0,10"/>

        <!--
            Button은 ViewModel의 SayHelloCommand 명령에 바인딩되어 있습니다.
            [RelayCommand] 특성이 적용된 SayHello() 메서드에 의해 SayHelloCommand 속성이 자동으로 생성됩니다.
            버튼을 클릭하면 SayHello() 메서드가 실행되고, 그 결과가 GreetingMessage에 저장됩니다.
        -->
        <Button Content="인사하기" Command="{Binding SayHelloCommand}" Margin="0,0,0,10"/>

        <!--
            TextBlock은 ViewModel의 GreetingMessage 속성을 바인딩하여 인사 메시지를 화면에 출력합니다.
            Name 속성 입력 → 버튼 클릭 → 인사 메시지 출력의 흐름을 확인할 수 있습니다.
        -->
        <TextBlock Text="{Binding GreetingMessage}" FontWeight="Bold" />
    </StackPanel>
</Window>