我想知道为什么MVVM光缺少命令与异步执行?我相信在很多情况下这可能会有用,所以让我说一个。
假设我们的UI包含一个包含多个屏幕的容器。用户可以关闭特定屏幕或具有多个屏幕的容器。假设用户已在容器上发出了关闭命令。返回的容器在每个屏幕上调用close命令,它需要等待屏幕关闭。实际上,这可能意味着验证数据。因此,我们需要发出异步调用以防止UI变得无法响应,我们还需要等待任务完成,才能继续。
所以,如果我们在Command
中有这样的东西public RelayCommand CloseCommand
{
get { return _closeCommand ?? _closeCommand = new RelayCommand( async () =>
{
foreach (var screen in Screens)
{
if (!await screen.CloseCommand.ExecuteAsync(null))
{
// do something
}
}
}) }
}
我们还可以在屏幕上公开其他方法,但在我看来它应该是RelayCommand的任务,因为它已经存在于那里。
或者有不同的方法来处理这种情况?
答案 0 :(得分:2)
可能是因为有很多不同的方法;我在my MSDN article on the subject中描述了一些方法。
异步生命周期命令特别棘手。类似于"关闭"必须仔细考虑命令。是否有迹象表明正在关闭?如果用户多次关闭会发生什么情况("关闭"特别是通常可以由操作系统或其他应用程序启动,即使"关闭按钮"已被禁用)?
答案 1 :(得分:0)
我发现这在某种程度上是在MVVM Light中创建异步命令的一种解决方案。 如果确实如此,它将用Task.Run包装异步方法。我们的包装方法必须验证它是否没有执行两次,并从较低的异步执行中捕获错误。
private bool isLoading;
public bool IsLoading
{
get { return isLoading; }
set
{
if (value != isLoading)
{
Set(ref isLoading, value);
//Used to refresh Commands CanExecute laying on IsLoading
CommandManager.InvalidateRequerySuggested();
}
}
}
private RelayCommand loadCommand;
public RelayCommand LoadCommand
{
get
{
return loadCommand ?? (loadCommand = new RelayCommand(
() => Task.Run(LoadAsync),
() => !IsLoading
));
}
}
private async Task LoadAsync()
{
//Prevents double execution in case of many mouse clicks on button
if (IsLoading)
{
return;
}
//Assignments which need to be done on UI tread
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
IsLoading = true;
});
try
{
list = await service.LoadAsync();
...
}
catch (Exception e)
{
...
}
finally
{
DispatcherHelper.CheckBeginInvokeOnUI(() =>
{
IsLoading = false;
});
}
}