1️⃣ CanExecute 개요

더보기

📚 Microsoft Docs: Microsoft CommunityToolkit MVVM - ObservableProperty

 

 

CanExecute 개요

 

CanExecute는 WPF의 ICommand 인터페이스에서 제공하는 기능으로,
명령(Command)이 실행 가능한지 여부를 판단하는 조건부 로직입니다.

 

 

사용 예시


상황 예시
입력이 없을 때 버튼 비활성화 이름 입력이 없으면 “인사” 버튼 비활성화
처리 중 중복 실행 방지 비동기 작업 중 같은 버튼 눌리지 않게 막기
조건이 맞을 때만 실행 체크박스가 체크될 때만 삭제 버튼 활성화 등

 

RelayCommand에 CanExecute 연동하는 방법

[RelayCommand(CanExecute = nameof(CanGreet))]  // → 이 속성 하나로 CanExecute 메서드 자동 연결됨
private void Greet()
{
    Debug.WriteLine($"안녕하세요, {userName}님!");
}

private bool CanGreet()
{
    return !string.IsNullOrWhiteSpace(userName);
}

 

 

 

 

 

2️⃣ 예제 - CanExecute

더보기

✔️ 1. 동작 시나리오

  1. 이름 입력
  2. 체크박스 및 라디오 버튼 활용
  3. 버튼 클릭시
  4. 인사 메시지 출력
  5. 그리고 메시지를 지우는 버튼을 ClearCommand로 구현하기
  6. 입력된 이름이 없을 경우 버튼을 비활성화 MVVM 패턴에서 UI 제어 흐름과 조건부 명령 실행(CanExecute) 개념을 실습
개념 설명
CanExecute 명령 실행 가능 여부를 제어하는 메서드
NotifyCanExecuteChanged( ) 바인딩된 버튼의 활성/비활성 상태를 실시간 갱신
자동 생성 명령 이름 SayHelloCommand (메서드 이름 + Command)

 


✔️
 2. CanExecute 구현

 

📁 2.1 프로젝트 구조

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

 

 

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

// MainViewModel 클래스는 MVVM 패턴에서 View와 데이터를 연결하는 역할을 합니다.
// CommunityToolkit의 ObservableObject를 상속하여 속성 변경 알림(INotifyPropertyChanged)을 자동 구현합니다.
public partial class MainViewModel : ObservableObject
{
    // 이름 입력을 저장하는 속성입니다.
    // [ObservableProperty]를 사용하면 name 필드에 대해 Name 속성이 자동 생성되며,
    // UI에서 바인딩 시 TextBox 등의 입력 변경이 자동 반영되고 변경 통지가 발생합니다.
    [ObservableProperty]
    private string? name;

    // 인사 메시지를 저장하는 속성입니다.
    // GreetingMessage 속성은 TextBlock에 바인딩되어 메시지를 화면에 출력합니다.
    [ObservableProperty]
    private string? greetingMessage;

    // 체크박스와 바인딩되어 정중한 인사를 할지 여부를 제어하는 속성입니다.
    [ObservableProperty]
    private bool isPolite;

    // 라디오 버튼과 바인딩되는 성별 선택 속성입니다.
    [ObservableProperty]
    private string? selectedGender;

    // 버튼 클릭 시 실행되는 명령 메서드입니다.
    // [RelayCommand] 특성을 붙이면 자동으로 SayHelloCommand 속성이 생성되어 XAML에서 바인딩 가능해집니다.
    // 또한 CanExecute 조건으로 CanSayHello 메서드를 연결하여, 이름이 입력되지 않으면 버튼이 비활성화됩니다.
    [RelayCommand(CanExecute = nameof(CanSayHello))]
    private void SayHello()
    {
        // 체크박스 값에 따라 인사말을 다르게 설정
        string greeting = isPolite ? "안녕하세요" : "하이";

        // 선택된 성별에 따라 호칭을 다르게 설정
        string? title = selectedGender switch
        {
            "남성" => "형님",
            "여성" => "누님",
            _ => "친구"
        };

        // 최종 인사 메시지를 구성하여 GreetingMessage 속성에 저장
        GreetingMessage = $"{greeting}, {Name} {title}!";
    }

    // SayHelloCommand의 실행 가능 여부를 판단하는 메서드입니다.
    // 이름이 입력되어 있어야 true 반환 → 버튼 활성화됨
    private bool CanSayHello()
    {
        return !string.IsNullOrWhiteSpace(Name);
    }

    // 이름이 변경될 때마다 SayHelloCommand의 CanExecute 상태를 업데이트하여
    // 버튼 활성화 여부를 즉시 반영합니다.
    partial void OnNameChanged(string? value)
    {
        SayHelloCommand.NotifyCanExecuteChanged();
    }

    // 메시지를 초기화하는 명령입니다.
    // 버튼과 ClearCommand로 바인딩되어 클릭 시 모든 속성을 기본값으로 되돌립니다.
    [RelayCommand]
    private void Clear()
    {
        GreetingMessage = string.Empty;
        Name = string.Empty;
        SelectedGender = null;
        IsPolite = false;
    }
}

 

🔍 2.3 XAML 화면 구성

<!-- MainViewModel을 현재 View의 데이터 컨텍스트로 설정합니다.
     이를 통해 XAML 내에서 ViewModel의 속성과 명령에 직접 접근할 수 있습니다. -->
<Window.DataContext>
    <vm:MainViewModel />
</Window.DataContext>

<StackPanel Margin="20" VerticalAlignment="Center">

    <!-- 사용자로부터 이름을 입력받는 TextBox입니다.
         Name 속성과 양방향 바인딩되며, 텍스트가 입력될 때마다 ViewModel의 속성이 자동 갱신됩니다. -->
    <TextBox Text="{Binding Name, UpdateSourceTrigger=PropertyChanged}" 
            />

    <!-- 성별 선택을 위한 라디오 버튼 그룹입니다.
         EqualsConverter를 사용해 SelectedGender 속성과 양방향으로 바인딩되며,
         남성/여성 중 하나를 선택할 수 있습니다. -->
    <TextBlock Text="성별 선택:"  />
    <StackPanel Orientation="Horizontal">
        <RadioButton Content="남성" GroupName="Gender" 
                     IsChecked="{Binding SelectedGender, Converter={StaticResource EqualsConverter}, ConverterParameter=남성}" />
        <RadioButton Content="여성" GroupName="Gender" 
                     IsChecked="{Binding SelectedGender, Converter={StaticResource EqualsConverter}, ConverterParameter=여성}" />
    </StackPanel>

    <!-- 체크박스를 통해 정중한 인사를 사용할지 여부를 설정합니다.
         IsPolite 속성과 바인딩되어 값이 ViewModel에 실시간 반영됩니다. -->
    <CheckBox Content="정중한 인사 사용" IsChecked="{Binding IsPolite}"/>

    <!-- SayHelloCommand에 바인딩된 버튼입니다.
         이름이 입력되어 있을 경우에만 활성화되며, 클릭 시 인사 메시지를 생성합니다. -->
    <Button Content="인사하기" Command="{Binding SayHelloCommand}"/>

    <!-- ClearCommand에 바인딩된 버튼입니다.
         클릭 시 모든 입력 값과 인사 메시지를 초기화합니다. -->
    <Button Content="메시지 초기화" Command="{Binding ClearCommand}" />

    <!-- ViewModel의 GreetingMessage 속성과 바인딩되어 생성된 인사 메시지를 표시합니다. -->
    <TextBlock Text="{Binding GreetingMessage}" FontSize="16" FontWeight="Bold" 
               TextWrapping="Wrap"/>
</StackPanel>

 

🔍 2.4 추가 클래스: EqualsConverter.cs (라디오버튼 바인딩을 위해 필요)

// EqualsConverter는 주로 WPF의 라디오 버튼과 ViewModel 속성 간 바인딩에 사용됩니다.
// MVVM 패턴에서 문자열 값을 비교하거나 특정 값과 매칭될 때 체크 상태를 결정할 수 있도록 도와주는 변환기입니다.
public class EqualsConverter : IValueConverter
{
    // Convert 메서드는 ViewModel의 속성 값(value)과 ConverterParameter를 비교하여,
    // 두 값이 같으면 true, 다르면 false를 반환합니다.
    // 이 값은 IsChecked 속성에 바인딩되어 라디오 버튼이 선택 상태인지 여부를 결정합니다.
    public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return value?.ToString() == parameter?.ToString();
    }

    // ConvertBack 메서드는 라디오 버튼이 선택되었는지를 나타내는 bool 값을 받아서,
    // true일 경우 해당 ConverterParameter 값을 ViewModel에 전달하고,
    // false일 경우 바인딩을 하지 않습니다(Binding.DoNothing).
    public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
    {
        return (bool)value ? parameter?.ToString() : Binding.DoNothing;
    }
}

 

🔍 2.5 XAML 화면 구성 App.xaml 어플리케이션 전역 리소스 등록

<Application.Resources>
    <!--
    EqualsConverter는 라디오 버튼의 선택 상태(IsChecked)와 ViewModel의 문자열 속성 간의 바인딩을 지원합니다.
    예: SelectedGender 속성이 "남성"일 때만 특정 라디오 버튼이 선택되도록 제어할 수 있습니다.

    이 리소스 등록은 View (XAML) 전역에서 EqualsConverter를 재사용할 수 있도록 메모리에 상주시키며,
    x:Key="EqualsConverter"를 통해 바인딩 시 참조할 수 있습니다.

    사용 예:
    <RadioButton Content="남성"
                 IsChecked="{Binding SelectedGender, Converter={StaticResource EqualsConverter}, ConverterParameter=남성}" />

    위 바인딩은 SelectedGender == "남성" 일 때 해당 라디오 버튼이 선택됨(IsChecked = true).
    반대로 해당 버튼을 선택하면 SelectedGender 속성 값이 "남성"으로 설정됩니다.
    -->
    <local:EqualsConverter x:Key="EqualsConverter"/>
</Application.Resources>