我正在研究.NET 4.5小型WPF / MVVM,我正在努力让一个进度条与async / await一起工作正确。
我已经把事情搞定了,但是我无法正确取消任务。或者,我认为任务可能会被取消,但无论如何,进度条都会全长运行。
我在“开始”和“停止”时调用“LongRun”方法,但在我想要停止时使用可选的取消令牌参数。这可能是一种不寻常的做事方式,但我认为它看起来没问题 - 至少在理论上: - )
以下是一些代码:
视图模型
public MainViewModel()
{
_progress = new Progress<int>(ReportProgress);
CountFilesCreatedCommand = new RelayCommand<IProgress<int>>(progress => LongRun(Progress));
_tokenSource = new CancellationTokenSource();
_tokenSource.Cancel();
StopCountFilesCommand = new RelayCommand<CancellationToken>(token => LongRun(Progress, _tokenSource.Token));
ProgressText = "...";
}
private void ReportProgress(int result)
{
PercentProgress = result;
}
private async void LongRun(IProgress<int> progress, CancellationToken token = default(CancellationToken))
{
try
{
// Start long running task here
int i = 0;
for (; i != 101; ++i)
{
if (token.IsCancellationRequested)
{
// This part of the code is executed when I
// try to stop the Task, I can see the "Cancelled!"
// text flicker for a second, and then the code
// resume to run
_tokenSource.Cancel();
progress?.Report(PercentProgress);
ProgressText = "Cancelled!";
}
await Task.Delay(TimeSpan.FromSeconds(0.1), token).ConfigureAwait(false);
progress?.Report(i);
ProgressText = i + "%";
}
}
catch (OperationCanceledException)
{
//throw;
}
}
XAML
<Grid xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation">
<StackPanel>
<!--<Button Margin="10,18,10,0" Content="Start Long Run" Height="30" Click="Button_Click_Async"/>-->
<ProgressBar x:Name="pbStatus" Margin="10,10,10,0" Height="30" IsIndeterminate="False" Visibility="Visible" Minimum="0" Maximum="100" Value ="{Binding PercentProgress, Mode=TwoWay}"/>
<TextBlock x:Name="tbResultat" Margin="0,10,0,10" HorizontalAlignment="Center" VerticalAlignment="Center" Text="{Binding ProgressText}" />
<DockPanel>
<Button Margin="10,0" Content="Start Long Run" Height="30" Width="200" Command="{Binding CountFilesCreatedCommand}"/>
<Button Margin="10,0" Content="Stop Long Run" Height="30" Width="200" HorizontalAlignment="Right" Command="{Binding StopCountFilesCommand}"/>
</DockPanel>
</StackPanel>
</Grid>
我觉得解决方案可能与XAML有关吗?
非常感谢任何帮助!
答案 0 :(得分:4)
我在“开始”和“停止”时调用“LongRun”方法,但在我想要停止时使用可选的取消令牌参数。
这就是你的问题所在。当您停止时,您希望现有对LongRun
的调用存在,而不是创建对LongRun
的新调用。
这样的事情会更合适(假设此操作只能执行一次,并且您根据需要启用/禁用按钮):
_progress = new Progress<int>(ReportProgress);
_tokenSource = new CancellationTokenSource();
CountFilesCreatedCommand = new RelayCommand(() => LongRun(_progress, _tokenSource.Token));
StopCountFilesCommand = new RelayCommand(() => _tokenSource.Cancel());
ProgressText = "...";
在旁注中,您应该avoid async void
(正如我在MSDN文章中所述)。 async void
具有笨拙的错误处理语义,不能单元测试。