如果正在运行,请取消异步任务并再次运行它(一种刷新行为)



我有一个包含两个DataGridView控件的窗体,每个控件都有一个刷新按钮。控件从两种方法(任务 1 和任务 2(获取数据。还有一个常规刷新按钮,用于重新填充这两个控件。 填充控件的两种方法不能同时运行并且非常耗时(每个大约 1 分钟(,因此我希望它们在后台运行以保持表单处于活动状态。 当我按下每个刷新按钮时,我想取消任何活动任务(如果它当前正在进行并重新开始(。

此外,我还实现了一个为每个方法填充的进度条。

到目前为止,我已经编写了以下代码:

  • 注意:编写这些任务仅用于测试使用async-awaitTask.Run的逻辑

public bool pending = false; // I have used a public boolean to determine if the tasks are in progress.
private async void Button1_Click(object sender, EventArgs e) 
{
var progress = new Progress<int>(value => { toolStripProgressBar1.Value = value; });
string test2 = "";
string test1 = "";
CancellationTokenSource source = new CancellationTokenSource();
if (pending)
{source.Cancel();}
pending = true;
await Task.Run(() =>
{
test1 = task1(progress, source.Token);
});
toolStripProgressBar1.Value = 0;
await Task.Run(() =>
{
test2 = task2(progress, source.Token);                
});
pending = false;
toolStripProgressBar1.Value = 0;
}
private string task1(IProgress<int> progress, CancellationToken token)
{
if (token.IsCancellationRequested)
{
return "cancelled";
}
for (int i = 0; i != 100; ++i)
{
if (progress != null)
progress.Report(i);
Thread.Sleep(100);
Console.WriteLine(i.ToString() + ";");
if (token.IsCancellationRequested)
{
return "cancelled";
}
}
return "task1";
}
private string task2(IProgress<int> progress, CancellationToken token)
{
if (token.IsCancellationRequested)
{
return "cancelled";
}
for (int i = 0; i != 100; ++i)
{
if (progress != null)
progress.Report(i);
Thread.Sleep(100);
Console.WriteLine(i.ToString() + ";");
if (token.IsCancellationRequested)
{
return "cancelled";
}
}
return "task2";
}
  • 注意:Button_1控件是常规刷新按钮,它依次运行这两种方法。 Button_2 和Button_3 Click 事件代码类似于 Button_1 Click 事件,但它只运行一个任务,而不是同时运行两个任务。为了保持代码干净,我没有把它们放在这里。

使用此代码,我得到以下行为。

  • 第一次单击Button_1 - 代码运行正常,进度条运行正常且完整。

  • 在进度条完成之前第二次单击Button_1(bool 挂起为 true( - 进度条重新启动,但立即恢复到初始进度,初始计数仍在运行,未被if (token.IsCancellationRequested)取消

  • 进度条完成之前第三次单击Button_1 - 进度条开始闪烁,初始计数仍在运行,另一个计数开始。

我知道代码不完整,因为我没有找到在取消方法后重新启动方法的方法。

分析到目前为止我是如何编写代码的,我不明白进度条的行为。另外,我不明白为什么当我第二次单击按钮时第一个计数仍在运行。 在再次调用任何正在运行的任务之前取消它们的最佳方法是什么?

每次单击该按钮时,都会重新初始化取消令牌。

source = new CancellationTokenSource();

我怀疑这扰乱了实现行为。 以前的"任务 1"任务继续运行,而新的"任务 1"任务被取消。

当"Task2"运行时,这更进一步,有两个任务正在执行。 这会导致进度条闪烁,因为每个任务都会在进度条上更新自己的值。

启动取消后,应等待,然后再重新启动新任务。

最新更新