这是WPF (.NET Framework4.8)。我需要在UI中提供两个<Button>
来启动和停止一个长期运行的后台进程。最初应该启用“开始”按钮,并在发出命令后将其禁用(以避免再次单击)。“停止”按钮最初将被禁用,并将在进程开始运行时启用。
我使用的是AsyncRelayCommand
在Windows社区工具包的MVVM库中提供的。这些按钮通过普通的XAML绑定绑定到它们的VM。底层命令如下所示:
private AsyncRelayCommand _StartPumpingCommand;
public AsyncRelayCommand StartPumpingCommand
{
get
{
_StartPumpingCommand ??= new AsyncRelayCommand(async (CancellationToken token) =>
{
dispatcher.Invoke(() => _CancelPumpingCommand.NotifyCanExecuteChanged());
await SomeTask(token);
},
() => {
/* SomeTask is not running and a cancellation has not been requested */
return !_StartPumpingCommand.IsRunning && !_StartPumpingCommand.IsCancellationRequested;
});
return _StartPumpingCommand;
}
}
private RelayCommand _CancelPumpingCommand;
public RelayCommand CancelPumpingCommand
{
get
{
_CancelPumpingCommand ??= new RelayCommand(() =>
{
if(_StartPumpingCommand?.IsRunning??false)
_StartPumpingCommand.Cancel();
},
() => _StartPumpingCommand?.IsRunning??false);
return _CancelPumpingCommand;
}
}
问题:
AsyncRelayCommand
内部是否包含CancellationTokenSource
魔术,还是需要自己在VM类中创建一个,并在上面的两个命令中使用它?StartPumpingCommand
的完成与CancelPumpingCommand
通信,从而相应地启用/禁用UI中的按钮?我们应该在CancelPumpingCommand.NotifyCanExecuteChanged()
返回后打电话给SomeTask()
吗?既然CancelPumpingCommand
使用StartPumpingCommand.IsRunning
属性来决定其可用性,那么它将如何运行,并且StartPumpingCommand
仍在运行,对吗?发布于 2022-11-07 14:34:09
弄明白了。以下是在Community中执行异步命令的正确方法,以防它帮助某人:
private AsyncRelayCommand _StartPumpingCommand;
public AsyncRelayCommand StartPumpingCommand
{
get
{
_StartPumpingCommand ??= new AsyncRelayCommand(async (CancellationToken token) =>
{
try
{
await Task.Run(() => SomeTask(token), token);
}
catch(OperationCanceledException)
{
//do whatever u want to do in case of task cancellation
}
},
() => !_StartPumpingCommand.IsRunning);
return _StartPumpingCommand;
}
}
private ICommand _CancelPumpingCommand;
public ICommand CancelPumpingCommand
{
get
{
_CancelPumpingCommand ??= StartPumpingCommand.CreateCancelCommand();
return _CancelPumpingCommand;
}
}
private async Task SomeTask(CancellationToken token)
{
//I'm using "await foreach" which requires C# 8 and an Nuget
//package named `Microsoft.Bcl.AsyncInterfaces` when targeting
//.NET Framework. You may use some other way of creating a
//Task here.
await foreach(...)
{
token.ThrowIfCancellationRequested();
//do stuff
}
}
这完全正确。我的UI是完全响应的(没有死锁),我可以取消和重新启动任务的任何次数。这表明AsyncRelayCommand
内部包含任务取消魔术,只需要一个可使用的方法即可工作。
https://stackoverflow.com/questions/74347185
复制相似问题