问题
I am wondering why is MVVM light missing command with async execution? I believe there are many cases where this could be useful, so let me name one.
Lets say that our UI contains one container that contains multiple screens. User can close a particular screen, or a container with multiple screens. Lets say that a user has issued a close command on the container. Container in return invokes close command on each screen, and it needs to wait for screen to be closed. This in practice can means validating data. saving, etc. For this reason we need to issue an async call to keep the UI from becoming unresponsive, and also we need to wait for task to complete, in order to continue.
So, if we have something like this in Command
public RelayCommand CloseCommand
{
get { return _closeCommand ?? _closeCommand = new RelayCommand( async () =>
{
foreach (var screen in Screens)
{
if (!await screen.CloseCommand.ExecuteAsync(null))
{
// do something
}
}
}) }
}
We could also expose additional method on screen, but in my opinion it should be task of RelayCommand, since it already exist there.
Or there is a different methodology to handle such scenario?
回答1:
Probably because there are many different ways of doing it; I describe a few approaches in my MSDN article on the subject.
Asynchronous lifetime commands are especially tricky. Something like a "close" command must be carefully considered. Is there some indication that a close is in progress? What happens if the user closes more than once ("close" in particular can often be initiated by an OS or another app even if a "close button" is disabled)?
回答2:
I found this being in some ways a solution to making async commands in MVVM Light. If fact it overwrap a async method with Task.Run. Our wrapped method has to verify if it not executed twice, and catches errors from lower async executions.
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;
});
}
}
来源:https://stackoverflow.com/questions/27699237/async-command-execution-in-mvvm-light