对我来说,学习MVVM的当前步骤是RelayCommand。
所以我想到了这个RelayCommand类:
中继命令类
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();
}
}
查看隐藏代码
要测试CanExecute
是对还是假,我创建了一个Click
事件,如果CanExecute == true
则调用Command或在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
在ViewModel中,我创建了Command,并添加了Thread.Sleep()
,以便canExecute
有时间向我展示来自Code-Behind
的ErrorMessage。
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);
});
}
现在的问题是,例如,如果我单击按钮5次,则MyCommandMetod()
被使用5次。因此CanExecute
将永远不会改变。
但是为什么它没有变化?
我这样理解RelayCommand:
例如,如果有人使用SpeedClicker并每秒点击1.000.000次,那么您就不会发送垃圾邮件。Button会单击该应用程序并使之崩溃。
答案 0 :(得分:1)
创建命令时,必须将一些can-execute-logic传递给命令:
public ViewModel()
{
MyCommand = new RelayCommand(MyCommandMethod, MyCanExecutePredicate);
}
private bool MyCanExecutePredicate( object commandParameter )
{
// TODO: decide whether or not MyCommandMethod is allowed to execute right now
}
示例:如果您一次只允许执行一个命令,则可以按照以下思路提出一些建议:
public async void MyCommandMethod(object obj)
{
_myCanExecute = false;
MyCommand.Refresh();
await Task.Run(() =>
{
Thread.Sleep(5000);
ErrorMessage.Error(obj as string);
});
_myCanExecute = true;
MyCommand.Refresh();
}
private bool MyCanExecutePredicate( object commandParameter )
{
return _myCanExecute;
}