WPF에서 ICommand를 구현해서 쓰실 텐데요, 여러분은 어떻게 구현 하시나요?

저는 이번에 아래와 같이 구현해 보았습니다.
※ Command Parameter 부분은 Converter를 통해 좀 더 보완해야 합니다.

여러분은 어떻게 사용하시나요?

    public class RelayCommand<TParam> : ICommand
    {
        private readonly Action<TParam> _execute;
        private readonly Predicate<TParam> _canExecute;

        /// <summary>
        /// 실행 가능 상태가 변경될 때 호출하도록 하면 되는데, 간단하게 구현하기 위해 CommandManager.RequerySuggested 이벤트와 연결시켰다.
        /// </summary>
        public event EventHandler CanExecuteChanged
        {
            add => CommandManager.RequerySuggested += value;
            remove => CommandManager.RequerySuggested -= value;
        }

        public RelayCommand(Action<TParam> execute, Predicate<TParam> canExecute = default)
        {
            _execute = execute ?? throw new ArgumentNullException(nameof(execute));
            _canExecute = canExecute ?? (_ => true);
        }

        public bool CanExecute(object parameter) => _canExecute((TParam)parameter);

        public void Execute(object parameter) => _execute((TParam)parameter);

        public static implicit operator RelayCommand<TParam>(Action<TParam> executeAction) => new(executeAction);
        public static implicit operator RelayCommand<TParam>((Action<TParam>, Predicate<TParam>) @params) => new(@params.Item1, @params.Item2);
    }

    public class RelayCommand : RelayCommand<object>
    {
        public RelayCommand(Action executeAction, Func<bool> canExecuteFunc = null) : base(_ => executeAction(), _ => canExecuteFunc())
        {
        }
    }

사용,

        public RelayCommand<string> ExecuteMenuCommand { get; } = new(p =>
        {
            MessageBox.Show(p);
        }, p => true);
4개의 좋아요

지금은 데브익스프레스 프레임워크 써서…처음 WPF MVVM 배울 때 말고는 해본 적이 없네요 ㅠㅠ

2개의 좋아요
public class RelayCommand<T> : ICommand
{
    readonly Action<T> _execute = null;
    readonly Predicate<T> _canExecute = null;

    public RelayCommand(Action<T> execute)
        : this(execute, null)
    {
    }

    public RelayCommand(Action<T> execute, Predicate<T> canExecute)
    {
        _execute = execute ?? throw new ArgumentNullException("execute");
        _canExecute = canExecute;
    }

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

    public event EventHandler CanExecuteChanged
    {
        add { CommandManager.RequerySuggested += value; }
        remove { CommandManager.RequerySuggested -= value; }
    }

    public void Execute(object parameter)
    {
        _execute((T)parameter);
    }
}
public MenuClickCommand { get; }

public ViewModel()
{
    MenuClickCommand = new RelayCommand<MenuModel>(MenuSelected, CanMenuSelected);
}

private MenuSelected(MenuModel menu)
{
    
}

private bool CanMenuSelected(MenuModel menu)
{
    return true;
}

@dimohy 저는 이렇게 사용하고 있는데요. :smile:
저도 최근에 ICommand를 좀 더 구현해볼 생각을 해보고 있었어요~

2개의 좋아요

저희 회사가 Prism과 ReactiveUI 라이브러리를 쓰고 있어서 내장된 DelegateCommand와 ReactiveCommand를 쓰고 있습니다.

DelegateCommand는 RelayCommand와 겉보기에는 차이가 없어 보이고 ReactiveCommand는 UI 쪽에서 사용할 수 있는 일부 요소와 결합해서 사용합니다.

아래에 예시를 들면…

public ReactiveCommand SomeCommand { get; }

public object Some
{
    get => _some;
    set => this.RaiseAndSetIfChanged(ref _some, value);  // BindableBase의 SetProperty()와 같은 역할
}

...

// command 사용가능 여부를 모니터링하는 변수(CanExecute와 같음)
var observerSome = this.WhenAnyValue(x => x.Some);

SomeCommand = ReactiveCommand.Create(SomeAction, observerSome, RxApp.MainThreadScheduler);
// Command에 구독 추가
SomeCommand.Subscribe(SomeSubscribe);
5개의 좋아요

ReactiveUI를 사용하는곳이 많지 않을텐데, 학습이 까다로우나 익숙해지면 유용한데, 멋집니다!

4개의 좋아요

참고로 Blazor에서도 ReactiveUI 쓸 수 있습니다!

4개의 좋아요

회사에 한 분이 도입하자고 하였고 그 분이 직접 세미나를 열어주셔서 도입하게 됐습니다 :slight_smile:

이름 그대로 UI에서 사용할 때 그 진가를 발휘하는 것 같아요.
간단한 경우에는 거의 사용하지 않고, 조금 복잡한 UI를 구성할 때, 또는 MVVM에서 UI 프로퍼티를 추적관리해야 할 때 좋은 것 같아요

5개의 좋아요

저희 회사도 비슷하기는한데…
ICommand같은 경우 Execute(...)를 비동기로 처리할 수 없는 그지 같음이 좀 있어서…
그 부분만 보여주신 코드와 다르고 비슷~ 한거 같습니다. ㅎㅎㅎ

아 근데 저는 CommandManager.RequerySuggested는 안씁니다.
WPF 전유물이기도 하고, 무한 콜 때리고 있는게 좀 골 때리는거 같아서요.

근데 사실 RelayCommandDelegateCommand 처럼 ICommand의 대리자는 쓰지 않고,
수행 하고자 하는 커맨드를 ICommand로부터 직접 상속 받아 하는 경우가 많은거 같습니다.

예를들어…

class LoginCommand : ICommand
{
  ...
}
5개의 좋아요

나중에 level120 님의 level120짜리 리엑티브 UI 강의 한 번 맛보고 싶습니다.

5개의 좋아요

하하 감사합니다 :slight_smile:
언제 준비가 끝날지 모르겠지만 잘 준비가 된다면 기회를 만들어보겠습니다 :laughing:

(예전에 비동기 부분을 정리하려고 한 것도 아직 다 못 끝내서… ㅜㅠ)

4개의 좋아요

관련 오픈소스도 함께 만들면 의미 있을 것 같네요. ㅋ

2개의 좋아요