RelayCommand는 MVVM 구조에서 메서드(Logic)를 실행하는 방법 입니다.
CommandParameter는  RelayCommand에 "매개변수"를 전달해 메서드(Logic)를 실행하는 방법 입니다.

 

1️⃣ CommandParameter 개요

더보기

📚 Microsoft DocsCommunityToolkit.Mvvm.Input.RelayCommand

 

 

CommandParameter 개요

  1. XAML에서 Button, MenuItem, ListBoxItem 등의 컨트롤이 명령(Command)을 실행할 수 있습니다.
    CommandParameter는 이때 추가적인 데이터를 전달하는 속성입니다.
  2. MVVM에서는 View와 ViewModel이 직접 연결되지 않도록 하기 위해,
    이벤트 기반의 직접 호출 대신(Button Click 이벤트에서 sender를 사용할 수 없음) Command를 사용합니다.
    Command는 기본적으로 매개변수를 받을 수 없습니다.

    따라서 어떤 객체인지 ViewModel로 직접 전달하기 위해 CommandParameter가 중간 매개체 역할을 합니다.

 


✅ CommandParameter 동작 구조

[View, XAML]
Button → Command="{Binding SomeCommand}"
         CommandParameter="{Binding Name}" />

↓ 클릭 시

[ViewModel]
void MyCommand(string name) { ... } 실행됨

 


✅ CommandParameter 사용 예시


구문 의미
CommandParameter="{Binding}" 현재 DataContext 객체 전체 전달
CommandParameter="{Binding Name}" 특정 속성만 전달
CommandParameter="정적 값" 고정된 텍스트 또는 숫자 전달
CommandParameter="{Binding SelectedItem, ElementName=MyList}" 다른 컨트롤 값 전달
Tuple, ValueTuple + Converter 사용 다중 값 전달 (MultiBinding)
CommandParameter="{x:Null}" 명시적으로 null 전달
*모든 사용 예시 케이스를 사용할 수 있어야 한다.

 

2️⃣  03CommandParameter - 예제

더보기

✔️ 1. 학습 목표

 

  • Step 1. 
    • ViewModel에서 동작할 비지니스 로직에, 매개변수를 전달받아 동작되도록 구현합니다.
  • Step 2.
    • View에서 특정 속성값을 매개변수로 전달받습니다.
  • Step 3.
    • 전달받은 값을 ViewModel 메서드 실행시 반영되는지 확인합니다.

 

 

 

✔️ 2. 동작 시나리오

  1. TextBox에서 입력받은 값을
  2. 버튼을 누를때, 컨트롤에서 전달받은 값을 ViewModel 메서드에 전달하여
  3. View에 다시 반영되도록 합니다. 

 

✔️ 2RelayCommand ]으로 구현

 

📁 2.1 프로젝트 구조

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

 

 

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

public partial class MainViewModel : ObservableObject
{
    // 사용자 이름 입력
    [ObservableProperty]
    private string? userName;

    // 인사 메시지 출력 결과
    [ObservableProperty]
    private string? greeting;

    // CommandParameter로 이름을 전달받아 인사 메시지를 설정하는 커맨드
    [RelayCommand]
    private void Greet(string name)
    {
        Greeting = $"안녕하세요, {name}님!";
        Debug.WriteLine(Greeting);
    }
}

 

 

📁  2.4 XAML 화면 구성

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

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

<StackPanel Margin="20">
    <!-- 사용자 이름 입력 -->
    <TextBox Text="{Binding UserName, UpdateSourceTrigger=PropertyChanged}" Margin="0 0 0 10" />

    <!-- 이름을 파라미터로 전달하여 인사 메시지 출력 -->
    <Button Content="인사하기"
            Command="{Binding GreetCommand}"
            CommandParameter="{Binding UserName}" />

    <!-- 인사 결과 출력 -->
    <TextBlock Text="{Binding Greeting}" FontSize="16" Margin="10 0 0 0"/>
</StackPanel>

 

3️⃣ 04CommandParameter - 예제

더보기

✔️ 1. 동작 시나리오

  1. 버튼 컨트롤에서 전달받은 값(이름)을 전달받아
  2. RelayCommand 에 전달
  3. 콘솔 출력

 

✔️ 2RelayCommand ]으로 구현

 

📁 2.1 프로젝트 구조

WpfMvvmToolkit04_RelayCommand02_Prams/
├── Models/
│   └── User.cs
├── ViewModels/
│   ├── MainViewModel.cs         
├── Views/
│   ├── MainWindow.xaml          ← 메인 뷰
│   ├── MainWindow.xaml.cs
└── App.xaml
    └── App.xaml.cs

 

🔍 2.2 Model 클래스 만들기

// User 클래스는 MVVM 아키텍처에서 Model 역할을 수행합니다.
// 이 클래스는 사용자 데이터를 표현하며, ViewModel과 Service에서 데이터를 주고받는 데 사용됩니다.
public class User
{
    // 사용자 이름을 저장하는 속성입니다.
    // 기본값은 빈 문자열로 초기화되어 있으며, 비어 있는 상태에서도 안전하게 사용 가능합니다.
    public string Name { get; set; } = string.Empty;
}

 

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

// MainViewModel 클래스는 MVVM 패턴에서 View와 Model 사이의 중개자 역할을 수행합니다.
// ObservableObject를 상속받아 INotifyPropertyChanged를 자동으로 구현하며,
// UI와 데이터 간의 바인딩이 실시간으로 동작하도록 지원합니다.
public partial class MainViewModel : ObservableObject
{
    // Users는 사용자 목록을 보관하는 ObservableCollection입니다.
    // ObservableCollection은 UI와 자동 동기화되며, ItemsControl 등과 바인딩할 때 자주 사용됩니다.
    public ObservableCollection<User> Users { get; } = new()
    {
        new User { Name = "홍길동" },
        new User { Name = "김철수" },
        new User { Name = "이영희" }
    };

    // GreetUser 명령은 XAML에서 Button의 Command와 바인딩됩니다.
    // 이 명령은 CommandParameter로 User 객체를 전달받아 처리할 수 있습니다.
    // CommunityToolkit.MVVM의 [RelayCommand] 특성을 사용하면 GreetUserCommand 속성이 자동 생성됩니다.
    [RelayCommand]
    private void GreetUser(User user)
    {
        // 전달받은 User 객체의 이름을 출력합니다.
        // 실습 환경에서는 콘솔 출력으로 확인하며, 실제 앱에서는 메시지 박스, 로그, 뷰에 바인딩된 속성 등으로 확장할 수 있습니다.
        Console.WriteLine($"Hello {user.Name}!");
    }
}

 

🔍 2.4 XAML 화면 구성

    Title="Greet Users" Height="300" Width="300">
<!-- MainViewModel을 현재 View의 데이터 컨텍스트로 설정하여 ViewModel의 속성과 명령을 바인딩할 수 있게 합니다. -->
<Window.DataContext>
    <vm:MainViewModel />
</Window.DataContext>

<StackPanel Margin="10">
    <!-- Users 컬렉션을 ItemsSource로 설정하여 사용자 목록을 동적으로 생성합니다. -->
    <ItemsControl ItemsSource="{Binding Users}">
        <ItemsControl.ItemTemplate>
            <DataTemplate>
                <!-- 각 User 항목을 수평으로 정렬하는 StackPanel로 구성합니다. -->
                <StackPanel Orientation="Horizontal" Margin="5">

                    <!-- 사용자 이름을 출력하는 TextBlock입니다. -->
                    <TextBlock Text="{Binding Name}" Width="100"/>

                    <!--사용자별 인사 버튼입니다.
                        Command: MainViewModel의 GreetUserCommand에 바인딩합니다.
                        RelativeSource를 통해 상위(Window)의 DataContext에서 명령을 찾습니다.
                        CommandParameter: 현재 항목(User 객체 전체)을 매개변수로 전달합니다.
                        결과적으로 버튼 클릭 시 해당 User 객체가 GreetUser(User user) 메서드에 전달됩니다.-->
                    <Button Content="인사하기"
                            Command="{Binding DataContext.GreetUserCommand, RelativeSource={RelativeSource AncestorType=Window}}"
                            CommandParameter="{Binding}" />
                </StackPanel>
            </DataTemplate>
        </ItemsControl.ItemTemplate>
    </ItemsControl>
</StackPanel>

 

✔️ 2.5 결과

  • 버튼을 클릭하면 해당 이름이 콘솔에 출력

 

 

 

 


4️⃣ 05CommandParameter="{Binding}" - 예제

더보기

✔️ 1. 예제의 ItemConrtol 살펴보기 (ListBox 등 동일)

<ItemsControl ItemsSource="{Binding Users}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" Margin="5">
                <TextBlock Text="{Binding Name}" Width="100"/>
                <Button Content="인사하기"
                    Command="{Binding DataContext.GreetUserCommand, RelativeSource={RelativeSource AncestorType=Window}}"
                    CommandParameter="{Binding}" />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

 

 

✔️ 1.1 ItemTemplate → DataTemplate 간략 예시

<DataTemplate>
    <StackPanel>
        <TextBlock Text="{Binding Name}" />
        <Button Command="{Binding DataContext.GreetUserCommand}",
                CommandParameter="{Binding}" />
    </StackPanel>
</DataTemplate>

*ItemTemplate 내부에는 하나의 Person 객체가 바인딩 됨
 

 

✔️ 1.2  CommandParameter="{Binding}" 

ListBox → People 컬렉션 바인딩
   └ ItemTemplate의 DataContext = 각 Person 객체를 바인딩
         └ Button.CommandParameter = 바인딩된 각 Person 객체 데이터
  • 현재 DataContext 객체 전체 전달
  • ItemTemplate 내의 DataContext, 즉 하나의 Person 객체

 

 

✔️ 1.3  Command="{Binding DataContext.GreetUserCommand}" 

[RelayCommand]
private void GreetUser(User user) // 바로 이 부분의 파라미터에 전달!
{
    Debug.WriteLine($"Hello {user.Name}!");
}

 


✔️ 1.4 CommandParameter 전달 구조 

[ListBox]
 ├── Person { Name = "홍길동" }
 │     └── Button → CommandParameter = Person("홍길동") → GreetUser(Person("홍길동"))
 ├── Person { Name = "김철수" }
 │     └── Button → CommandParameter = Person("김철수") → GreetUser(Person("김철수"))
 └── Person { Name = "이영희" }
       └── Button → CommandParameter = Person("이영희") → GreetUser(Person("이영희"))

 

 

✔️ 2. 참고

 

✔️ 3. 참고

  • {Binding}을 생략하면, Command는 실행되지만 person 파라미터는 null 이 됩니다.
  • CommandParameter="{Binding Name}" 과 같이 사용하시면,
    메서드 시그니처도 ShowPerson(string name)처럼 변경합니다.


4️⃣ RelativeSource={RelativeSource AncestorType=Window} 사용 이유

더보기

* ListBox, DataGrid, ComboBox 등의 ItemTemplate 내부 Command 바인딩 시 필수

 

✔️ 1. 예제의 ItemConrtol 살펴보기 (ListBox 등 동일)

<ItemsControl ItemsSource="{Binding Users}">
    <ItemsControl.ItemTemplate>
        <DataTemplate>
            <StackPanel Orientation="Horizontal" Margin="5">
                <TextBlock Text="{Binding Name}" Width="100"/>
                <Button Content="인사하기"
                    Command="{Binding DataContext.GreetUserCommand, RelativeSource={RelativeSource AncestorType=Window}}"
                    CommandParameter="{Binding}" />
            </StackPanel>
        </DataTemplate>
    </ItemsControl.ItemTemplate>
</ItemsControl>

 

 

✔️ 1.1 ItemTemplate → DataTemplate → Button 간략 예시

<Button Content="인사하기"
    Command="{Binding DataContext.GreetUserCommand, RelativeSource={RelativeSource AncestorType=Window}}"
    CommandParameter="{Binding}" />

 

  • Command=...는 ViewModel에 있는 ShowPersonCommand를 찾아야 하지만
    이 버튼은 ListBox.ItemTemplate 내부에 있어서, 기본적으로 Person을 DataContext로 바라보고 있음
  • CommandParameter="{Binding}"는 여전히 Person 객체 → 즉 항목 자체만 접근 가능
    그래서 RelativeSource를 써서 Window의 DataContext(ViewModel)에서 접근함

 

 

✔️ 1.2  RelativeSource={RelativeSource AncestorType=Window

[Window]
 └── DataContext = MainViewModel
      └── ShowPersonCommand       ⬅ 이걸 찾기 위해 RelativeSource 사용

[ListBox ItemsSource=People]
 ├── ItemTemplate
 │    └── DataContext = Person ("홍길동", "김철수" 등)
 │         └── Button.Command = MainViewModel.ShowPersonCommand  ⬅ 이걸 찾기 위해 RelativeSource 사용
 │         └── Button.CommandParameter = 해당 Person ("홍길동", "김철수" 등) 객체

구성 설명
RelativeSource 바인딩 기준을 상대적으로 설정함
AncestorType=Window Button의 부모 계층을 타고 올라가면서 가장 가까운 Window를 찾음
DataContext.____Command 그 Window의 DataContext(ViewModel)에 있는 명령을 사용하겠다는 의미

 

 

✔️ 1.3 대안 - ElementName 바인딩 (명시적 이름 바인딩)

<Window x:Name="MainWin">
    <Button Command="{Binding DataContext.SomeCommand, ElementName=MainWin}" />
</Window>

* UI 요소의 이름을 기준으로 바인딩

 

 

 


5️⃣ 참고

더보기
  • {Binding}을 생략하면, Command는 실행되지만 person 파라미터는 null 이 됩니다.
  • CommandParameter="{Binding Name}" 과 같이 사용하시면,
    메서드 시그니처도 ShowPerson(string name)처럼 변경합니다.