저는 이번에 아래와 같이 구현해 보았습니다.
※ 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 저는 이렇게 사용하고 있는데요.
저도 최근에 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개의 좋아요
회사에 한 분이 도입하자고 하였고 그 분이 직접 세미나를 열어주셔서 도입하게 됐습니다
이름 그대로 UI에서 사용할 때 그 진가를 발휘하는 것 같아요.
간단한 경우에는 거의 사용하지 않고, 조금 복잡한 UI를 구성할 때, 또는 MVVM에서 UI 프로퍼티를 추적관리해야 할 때 좋은 것 같아요
5개의 좋아요
저희 회사도 비슷하기는한데…
ICommand
같은 경우 Execute(...)
를 비동기로 처리할 수 없는 그지 같음이 좀 있어서…
그 부분만 보여주신 코드와 다르고 비슷~ 한거 같습니다. ㅎㅎㅎ
아 근데 저는 CommandManager.RequerySuggested
는 안씁니다.
WPF 전유물이기도 하고, 무한 콜 때리고 있는게 좀 골 때리는거 같아서요.
근데 사실 RelayCommand
나 DelegateCommand
처럼 ICommand의 대리자는 쓰지 않고,
수행 하고자 하는 커맨드를 ICommand
로부터 직접 상속 받아 하는 경우가 많은거 같습니다.
예를들어…
class LoginCommand : ICommand
{
...
}
5개의 좋아요
나중에 level120 님의 level120짜리 리엑티브 UI 강의 한 번 맛보고 싶습니다.
5개의 좋아요
하하 감사합니다
언제 준비가 끝날지 모르겠지만 잘 준비가 된다면 기회를 만들어보겠습니다
(예전에 비동기 부분을 정리하려고 한 것도 아직 다 못 끝내서… ㅜㅠ)
4개의 좋아요
관련 오픈소스도 함께 만들면 의미 있을 것 같네요. ㅋ
2개의 좋아요