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

Noo*_*ion 7 c# multithreading goto return exception

我是一个非常缺乏经验的 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
        }
    }
Run Code Online (Sandbox Code Playgroud)

现在我需要制作一个按钮,使用户能够取消测量,以便更改某些输入或参数,然后重新启动测量。所以我添加了一个“取消”按钮。

    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();            
    }
Run Code Online (Sandbox Code Playgroud)

现在我不知道如何管理程序的流程。我试图try-catch在 中创建一个结构button1_Click()并从 中抛出异常button7_Click,但它没有到达button1_Click()
然后我尝试measurements()在新线程上运行。但该线程无法访问我的主窗体上的 70 个 UI 项目。
即使我也不会像尝试后藤那样堕落。

我需要的是关于如何在这种情况下进行编程的建议,以便更好地控制应用程序,并且不会因异常和 Goto 等危险内容而损害程序流程。

tom*_*dox 5

如果您想中途取消实际任务,那么您需要考虑使用 CancellationTokenSource 并将取消令牌传递到异步方法中。

这是微软的文档,在底部附近有一个很好的例子,这是另一个关于显示进度条和允许取消的好博客。第二篇文章有很好的概述:

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

  1. 调用者创建一个 CancellationTokenSource 对象。
  2. 调用者调用可取消的异步 API,并从 CancellationTokenSource (CancellationTokenSource.Token) 传递 CancellationToken。
  3. 调用者使用 CancellationTokenSource 对象 (CancellationTokenSource.Cancel()) 请求取消。
  4. 任务确认取消并自行取消,通常使用 CancellationToken.ThrowIfCancellationRequested 方法。

为了使您的应用程序快速响应取消请求,您需要在长期运行的方法中定期检查取消令牌,并在请求取消时做出相应的响应。

  • 我现在让它工作得很好,但必须创建一个看起来像这样的结构;for (int wait = 0; wait < 120; wait++) { 等待 Task.Delay(1000); ct.ThrowIfCancellationRequested(); } (2认同)