반응형
해당 포스팅은 개인적으로 C# WPF를 공부하면서 익힌 내용을 기억에 남기기 위한 작업의 일환으로 작성된 글로서
일부 내용에 오류가 있을 수도 있으니 참고하시기 바랍니다.

 

 

C#WPF에서 MVVM패턴으로 
프로그래밍 할때 ICommand
인터페이스의 역할에 대해
알아보자.
반응형
내용 요약

 

MVVM 패턴에서 ICommand 인터페이스는 UI의 이벤트(예: 버튼 클릭)를 ViewModel로 전달하는 중요한 역할을 한다. 이는 MVVM 패턴의 핵심 원칙인 View와 ViewModel 간의 분리를 실현하는 데 필수적이다. 이번 글에서는 ICommand의 개념과 활용 방법, 그리고 실제 구현 사례를 통해 이를 자세히 알아보도록 하자.

 

목차

1.ICommand 인터페이스란 무엇인가?
2.ICommand의 주요 구성 요소
3.ICommand의 구현 방법
4.RelayCommand(DelegateCommand)의 활용
5.Command와 Data Binding의 연결
6.ICommand 사용 예제
   - 기본 구현
   - 파라미터 전달
   - CanExecute와 UI 상태 관리
7.ICommand와 MVVM의 관계
8.ICommand 구현의 장점과 한계

 

 

1.ICommand 인터페이스란 무엇인가?

 

ICommand는 WPF의 System.Windows.Input 네임스페이스에 정의된 인터페이스로, 버튼 클릭, 메뉴 항목 선택과 같은 사용자 입력을 처리하기 위해 사용된다. 이 인터페이스는 UI에서 발생한 이벤트를 ViewModel의 메서드로 연결할 수 있는 방법을 제공다.

 

public interface ICommand
{
    event EventHandler CanExecuteChanged;

    bool CanExecute(object parameter);
    void Execute(object parameter);
}

 

핵심 목적:

  • UI 이벤트를 처리하는 로직을 ViewModel에 두어 View와 ViewModel 간의 강한 결합을 방지함.
  • Binding을 통해 명령을 연결하여 코드 숨김(Code-Behind)을 최소화함.

 

2.ICommand의 주요 구성 요소

 

 

  • Execute 메서드
    • 명령 실행 시 호출되는 메서드
    • 예를 들어, 버튼이 클릭되었을 때의 동작을 정의함.
  • CanExecute 메서드
    • 명령 실행 가능 여부를 결정하는 메서드.
    • 반환값이 true일 때만 명령이 실행됨.
    • UI 요소(예: 버튼)의 활성화 상태를 제어함.
  • CanExecuteChanged 이벤트
    • CanExecute의 반환값이 변경될 때 UI 요소에 알림.
    • 일반적으로 ViewModel에서 상태 변화가 발생하면 호출됨.

 

 

3.ICommand의 구현 방법

 

ICommand 인터페이스를 직접 구현하려면 다음과 같이 작성한다.

using System;
using System.Windows.Input;

public class CustomCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;

    public event EventHandler CanExecuteChanged;

    public CustomCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _execute = execute ?? throw new ArgumentNullException(nameof(execute));
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

 

4.RelayCommand(DelegateCommand)의 활용

 

ICommand의 구현은 반복적이고 번거로울 수 있다. 따라서 이를 간소화하기 위해 RelayCommand 또는 DelegateCommand를 사용하는 것이 일반적이다. RelayCommand는 다음과 같이 정의된다.

public class RelayCommand : ICommand
{
    private readonly Action<object> _execute;
    private readonly Func<object, bool> _canExecute;

    public event EventHandler CanExecuteChanged;

    public RelayCommand(Action<object> execute, Func<object, bool> canExecute = null)
    {
        _execute = execute;
        _canExecute = canExecute;
    }

    public bool CanExecute(object parameter)
    {
        return _canExecute == null || _canExecute(parameter);
    }

    public void Execute(object parameter)
    {
        _execute(parameter);
    }

    public void RaiseCanExecuteChanged()
    {
        CanExecuteChanged?.Invoke(this, EventArgs.Empty);
    }
}

 

5.Command와 Data Binding의 연결

 

View에서 Command를 바인딩하여 버튼 클릭 등의 UI 동작을 ViewModel로 연결할 수 있다.

<Button Content="Click Me" Command="{Binding MyCommand}" />

 

public class MyViewModel
{
    public ICommand MyCommand { get; }

    public MyViewModel()
    {
        MyCommand = new RelayCommand(ExecuteCommand, CanExecuteCommand);
    }

    private void ExecuteCommand(object parameter)
    {
        // 버튼 클릭 시 실행할 로직
        MessageBox.Show("Button Clicked!");
    }

    private bool CanExecuteCommand(object parameter)
    {
        // 버튼 활성화 여부
        return true;
    }
}

 

6.ICommand 사용 예제

기본 구현

1.ViewModel에서 Command 정의

public ICommand SaveCommand { get; }

public MyViewModel()
{
    SaveCommand = new RelayCommand(Save, CanSave);
}

private void Save(object parameter)
{
    // 저장 로직
    Console.WriteLine("Data Saved!");
}

private bool CanSave(object parameter)
{
    // 조건: 데이터를 저장할 수 있는지 여부
    return !string.IsNullOrEmpty(SomeData);
}

 

2.XAML에서 바인딩

<Button Content="Save" Command="{Binding SaveCommand}" />

 

파라미터 전달

CommandParameter 속성을 사용하여 추가 데이터를 전달할 수 있습니다.

 

<XAML 코드>

<Button Content="Delete" Command="{Binding DeleteCommand}" CommandParameter="{Binding SelectedItem}" />

 

<ViewModel 코드>

public ICommand DeleteCommand { get; }

public MyViewModel()
{
    DeleteCommand = new RelayCommand(Delete, CanDelete);
}

private void Delete(object parameter)
{
    var item = parameter as MyItem;
    if (item != null)
    {
        Items.Remove(item);
    }
}

private bool CanDelete(object parameter)
{
    return parameter is MyItem;
}

 

7.ICommand와 MVVM의 관계

 

 

ICommand는 MVVM의 원칙인 관심사의 분리를 실현한다.

모든 로직(ViewModel에 위치)은 테스트 가능하며, UI 이벤트(View에 위치)는 ViewModel에 종속되지 않는다.

 

 

8.ICommand 구현의 장점과 한계

 

장점

View와 ViewModel의 강한 결합 제거: 로직이 ViewModel에 있어 재사용성과 유지보수성이 향상됩니다.

테스트 가능성: 명령 로직을 단위 테스트할 수 있습니다.

UI 상태 관리: CanExecute를 통해 UI의 활성화 상태를 동적으로 제어할 수 있습니다.

한계

구현 시 코드가 장황해질 수 있음. 이를 완화하기 위해 RelayCommand를 활용합니다.

복잡한 명령 체계에서는 추가적인 관리 코드가 필요합니다.

 


결론 및 개인적인 생각

 

ICommand는 WPF MVVM 패턴에서 사용자 입력을 처리하는 강력한 도구입니다. 이를 올바르게 구현하면 View와 ViewModel 간의 결합을 줄이고, 재사용 가능한 구조를 설계할 수 있습니다.

 

개인적으로, 처음에는 ICommand의 복잡함에 좌절했지만, RelayCommand 같은 도구를 활용하면서 효율적으로 코드를 작성할 수 있게 되었다. 특히, UI 상태를 동적으로 관리할 수 있는 기능은 사용자 경험을 향상시키는 데 매우 유용하다고 느껴졌다. ICommand를 이해하고 활용한다면 MVVM 패턴의 강점을 더욱 잘 느낄 수 있을 것이다.

반응형

+ Recent posts