簡體   English   中英

如何在C#Winforms應用程序中取消長時間運行的異步任務的執行

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

我是一個經驗不足的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();            
    }

現在我不知道如何管理程序的流程。 我試圖在button1_Click()創建一個try-catch結構,並從button7_Click引發異常,但是它無法傳遞到button1_Click()
然后,我嘗試在新線程上運行measurements() 但是該線程無法訪問我的主窗體上的70多個UI項目。
甚至我也不會像嘗試Goto那樣陷入低谷。

我需要的是關於如何在這種情況下進行編程的建議,以便對應用程序有一個良好的控制,而不會因為異常和Goto之類的風險而損害程序的流程。

如果要中途取消實際任務,則需要查看使用CancellationTokenSource並將取消令牌傳遞到異步方法中。

這是有關該文檔的Microsoft文檔 ,在底部有一個很好的例子, 這是另一個很好的博客 ,展示了進度條並允許取消。 第二篇文章有一個很好的概述:

取消由CancellationToken結構控制。 您可以在可取消異步方法的簽名中公開取消令牌,從而使它們可以在任務和調用方之間共享。 在最常見的情況下,取消遵循以下流程:

  1. 調用方創建一個CancellationTokenSource對象。
  2. 調用方調用可取消的異步API,並從CancellationTokenSource(CancellationTokenSource.Token)傳遞CancellationToken。
  3. 調用方使用CancellationTokenSource對象(CancellationTokenSource.Cancel())請求取消。
  4. 任務確認取消並自行取消,通常使用CancellationToken.ThrowIfCancellationRequested方法。

為了使您的應用對取消請求做出快速響應,您需要使用長期運行的方法定期檢查取消令牌,並在請求取消的情況下做出相應的響應。

這是一些粗糙的代碼,但是應該可以解決問題。

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM