我遇到了一个奇怪的案子,我被困在上面。
我有一个Popup View + ViewModel作为一个按钮。 Popup从其他视图获取Command以执行按钮。
现在,我想在单击后立即禁用该按钮,运行该命令然后禁用它。
这就是我现在拥有的:
PopupViewModel
public override Task InitializeAsync(object navigationData)
{
PopupModel model = (PopupModel) navigationData;
...
_mainActionCommandToRun = model.MainActionCommand;
...
return base.InitializeAsync(navigationData);
}
private void OnMainActionCommand(object obj)
{
MainActionCommand.CanExecute(false);
_mainActionCommandToRun.Execute(null);
MainActionCommand.CanExecute(true);
}
一些查看如何使用弹出窗口
await DialogService.ShowPopupAsync<PopupViewModel>(new PopupModel
{
...
MainActionCommand = new Command(
() =>
{
DoSomeThing();
})
});
这个案子就像一个魅力。分配给命令的操作是异步时,它会变得复杂。
一些具有异步操作的视图
await DialogService.ShowPopupAsync<PopupViewModel>(new PopupModel
{
...
MainActionCommand = new Command(
async () =>
{
await DoSomeThing();
})
});
在这种情况下,_mainActionCommandToRun.Execute(null)将触发异步操作并继续执行CanExecute(true)。
我无法等待执行,因为它是一个void方法,用任务包装它不会解决任何问题......
基本上,我有一个异步方法,不知道它是一个异步方法。
你需要一些asynchronous command的概念。如今,一些MVVM库内置了这个:
public interface IAsyncCommand : ICommand
{
Task ExecuteAsync(object parameter);
}
ICommand.Execute
实施总是async void ICommand.Execute(object parameter) => await ExecuteAsync(parameter)
。然后你可以定义你自己的AsyncCommand
,就像Command
一样,除了它实现了IAsyncCommand
。
然后让你的视图模型公开IAsyncCommand
而不是ICommand
,你的弹出逻辑可以使用:
private async void OnMainActionCommand(object obj)
{
MainActionCommand.CanExecute(false);
await _mainActionCommandToRun.ExecuteAsync(null);
MainActionCommand.CanExecute(true);
}