简体   繁体   English

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

[英]How to cancel execution of a long-running async task in a C# Winforms app

I'm a quite inexperienced c# programmer and need help on managing the flow of my program. 我是一个经验不足的C#程序员,在管理程序流程方面需要帮助。 It is a WinFormApp that asks for multiple user inputs and then uses them to establish serial communication with a device in order to make measurements. 它是一个WinFormApp,它要求多个用户输入,然后使用它们与设备建立串行通信以进行测量。 The measurements are made in an async method that takes about 20 minutes to run. 使用异步方法进行测量,大约需要20分钟才能运行。 So I'm using 所以我在用

    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
        }
    }

Now I need to make a button which enables the user to cancel the measurements in order to change some input or parameter and then restart the measurements. 现在,我需要创建一个按钮,使用户可以取消测量,以更改某些输入或参数,然后重新启动测量。 So I added a "Cancel"-button. 因此,我添加了“取消”按钮。

    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();            
    }

Now I do not know how to manage the flow of the program. 现在我不知道如何管理程序的流程。 I have tried to make a try-catch structure in button1_Click() and throw an Exception from button7_Click , but it doesn't get through to button1_Click() . 我试图在button1_Click()创建一个try-catch结构,并从button7_Click引发异常,但是它无法传递到button1_Click()
Then I tried to run measurements() on a new thread. 然后,我尝试在新线程上运行measurements() But the thread does not have access to 70-ish UI items on my main form. 但是该线程无法访问我的主窗体上的70多个UI项目。
And even I wont sink as low as trying Goto. 甚至我也不会像尝试Goto那样陷入低谷。

What I need is advice on how you would program in this situation in order to get a good control of the application and not compromise the flow of the program with risky stuff like exceptions and Goto. 我需要的是关于如何在这种情况下进行编程的建议,以便对应用程序有一个良好的控制,而不会因为异常和Goto之类的风险而损害程序的流程。

If you want to cancel the actual task midway through then you need to look at using a CancellationTokenSource and passing a cancellation token into your async method. 如果要中途取消实际任务,则需要查看使用CancellationTokenSource并将取消令牌传递到异步方法中。

This is the Microsoft documentation on that which has a good example near the bottom and this is another good blog on showing a progress bar and allowing cancellation. 这是有关该文档的Microsoft文档 ,在底部有一个很好的例子, 这是另一个很好的博客 ,展示了进度条并允许取消。 that second article has a good overview: 第二篇文章有一个很好的概述:

Cancellation is controlled by the CancellationToken structure. 取消由CancellationToken结构控制。 You expose cancellation tokens in the signature of cancelable async methods, enabling them to be shared between the task and caller. 您可以在可取消异步方法的签名中公开取消令牌,从而使它们可以在任务和调用方之间共享。 In the most common case, cancellation follows this flow: 在最常见的情况下,取消遵循以下流程:

  1. The caller creates a CancellationTokenSource object. 调用方创建一个CancellationTokenSource对象。
  2. The caller calls a cancelable async API, and passes the CancellationToken from the CancellationTokenSource (CancellationTokenSource.Token). 调用方调用可取消的异步API,并从CancellationTokenSource(CancellationTokenSource.Token)传递CancellationToken。
  3. The caller requests cancellation using the CancellationTokenSource object (CancellationTokenSource.Cancel()). 调用方使用CancellationTokenSource对象(CancellationTokenSource.Cancel())请求取消。
  4. The task acknowledges the cancellation and cancels itself, typically using the CancellationToken.ThrowIfCancellationRequested method. 任务确认取消并自行取消,通常使用CancellationToken.ThrowIfCancellationRequested方法。

To make your app respond quickly to a cancel request you need to then check the cancellation token regularly in your long running method and respond to it accordingly if a cancellation has been requested. 为了使您的应用对取消请求做出快速响应,您需要使用长期运行的方法定期检查取消令牌,并在请求取消的情况下做出相应的响应。

This is some rough code, but it should do the trick. 这是一些粗糙的代码,但是应该可以解决问题。

Using CancellationToken. 使用CancellationToken。 I've used a toggle method to test if the async task is to be cancelled. 我已经使用了切换方法来测试是否要取消异步任务。

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.          
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM