如何在C#Winforms应用程序中取消长时间运行的异步任务的执行

时间:2016-01-28 11:46:09

标签: c# multithreading exception return goto

我是一个非常缺乏经验的c#程序员,需要帮助来管理我的程序流程。它是一个WinFormApp,它要求多个用户输入,然后使用它们与设备建立串行通信以进行测量。测量是在异步方法中进行的,运行大约需要20分钟。所以我正在使用

    void main()
    {
        //Setup
    }

    private void button1_Click(object sender, EventArgs e)
    {
        await measurements();
        //Plot results
    }

    private async Task measurements()
    {
        while(true){
        //Make some measurements
        await Task.Delay(120000);
        //Make measurements, present data in the UI form.
        //return if done
        }
    }

现在我需要创建一个按钮,使用户可以取消测量以更改某些输入或参数,然后重新开始测量。所以我添加了一个"取消" - 按钮。

    private void button7_Click(object sender, EventArgs e)
    {
        textBox64.Enabled = true;
        button6.Enabled = true;
        button5.Enabled = true;
        textBox63.Enabled = true;
        button3.Enabled = true;
        trackBar1.Enabled = true;
        timer.Enabled = true;
        button7.Enabled = false;
        clearData();
        // measurement.Stop();            
    }

现在我不知道如何管理程序的流程。我试图在try-catch中设置button1_Click()结构并从button7_Click中抛出异常,但它没有通过button1_Click()
然后我尝试在新线程上运行measurements()。但是线程无法访问我主表单上的70-ahh UI项目 甚至我也不会像尝试Goto一样低沉。

我需要的是关于如何在这种情况下进行编程以获得对应用程序的良好控制并且不会因异常和Goto等风险事件而损害程序流程的建议。

2 个答案:

答案 0 :(得分:3)

如果你想在中途取消实际任务,你需要查看使用CancellationTokenSource并将取消令牌传递给你的异步方法。

This is the Microsoft documentation在底部附近有一个很好的示例,this is another good blog显示进度条并允许取消。第二篇文章有一个很好的概述:

  

取消由CancellationToken结构控制。您   在可取消的异步签名中公开取消令牌   方法,使它们在任务和调用者之间共享。在   最常见的情况是取消遵循此流程:

     
      
  1. 调用者创建一个CancellationTokenSource对象。
  2.   
  3. 调用者调用可取消的异步API,然后传递   CancellationToken来自CancellationTokenSource   (CancellationTokenSource.Token)。
  4.   
  5. 调用者使用CancellationTokenSource请求取消   object(CancellationTokenSource.Cancel())。
  6.   
  7. 该任务承认取消并通常取消   使用CancellationToken.ThrowIfCancellationRequested方法。
  8.   

要让您的应用快速响应取消请求,您需要在长时间运行的方法中定期检查取消令牌,并在请求取消时相应地回复。

答案 1 :(得分:2)

这是一些粗略的代码,但它应该可以解决问题。

使用CancellationToken。 我使用了切换方法来测试是否要取消异步任务。

CancellationTokenSource cts;

private async button1_Click(object sender, EventArgs e)
{
    toggleAsyncTask(false)
}

private void toggleAsyncTask(bool isCancelled){

    if(cts==null)
        var cts = new CancellationTokenSource();
    if(!isCancelled)
    {
        await measurements(cts.Token);
    }
    else
    {
        cts.Cancel();
        cts.Dispose();
        cts = null;
    }

}

private async Task measurementsOne(CancellationToken token)
{
    try
    {
        while(true){
            //Make some measurements
            await Task.Delay(120000); // don't know if you need this.
            //Make measurements, present data in the UI form.
            //return if done
    }
    catch(OperationCancelledException)
    {
        // to do if you please.
    }
}

private void button7_Click(object sender, EventArgs e)
{
    // button stuff
    toggleAsyncTask(true); // isCancelled is true.          
}