The current step of learning MVVM is RelayCommand for me.
So i came up with this RelayCommand class:
Relay Command class
public class RelayCommand : ICommand
{
private readonly Action<object> _execute;
private readonly Func<object, bool> _canExecute;
public RelayCommand(Action<object> execute) : this(execute, null)
{
}
public RelayCommand(Action<object> execute, Func<object, bool> canExecute)
{
_execute = execute ?? throw new ArgumentNullException(nameof(execute));
_canExecute = canExecute ?? (x => true);
}
public bool CanExecute(object parameter)
{
return _canExecute(parameter);
}
public void Execute(object parameter)
{
_execute(parameter);
}
public event EventHandler CanExecuteChanged
{
add => CommandManager.RequerySuggested += value;
remove => CommandManager.RequerySuggested -= value;
}
public void Refresh()
{
CommandManager.InvalidateRequerySuggested();
}
}
View Code-Behind
To test if CanExecute
is true or false, I created a Click
Event which is calling the Command if CanExecute == true
or Show an Error Message when CanExecute == false
.
if (sender is Button button)
{
if (_viewModel.MyCommand.CanExecute(button.Tag)) // Also testet to set this parameter `null`
_viewModel.MyCommand.Execute(button.Tag);
else
ErrorMessage.Error("CanExecute = false");
}
ViewModel
In my ViewModel I created the Command and added a Thread.Sleep()
to have time that canExecute
can show me the ErrorMessage from the Code-Behind
.
public ICommand MyCommand { get; set; }
public ViewModel()
{
MyCommand = new RelayCommand(MyCommandMethod);
}
public async void MyCommandMethod(object obj)
{
await Task.Run(() =>
{
Thread.Sleep(5000);
ErrorMessage.Error(obj as string);
});
}
The Problem now is, that if I click the Button 5 times for example, that MyCommandMetod()
is used 5 times. So CanExecute
will never change.
But why isn't it changing?
I understand RelayCommand as this:
- 1st - Button is clicked
- 2nd - canExecute = false (wait till process is finished)
- 3rd - canExecute = true
- 4th - Button can be executed again.
So that u can't spam Button clicks and crash the application if for example someone use SpeedClicker and clicks 1.000.000 times a seconds or so.
You have to pass some can-execute-logic to the command when creating it:
Example: if you want to allow only one command execution at a time, you could come up with something along these lines: