C# 异步取消

// .net8 Winform
using System;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace Async_Cancell
{
    public partial class Form1 : Form
    {
        // [ 1: 使用变量控制进程 ]
        // static bool Stop;  // 新建一个布尔值,用于在循环的任务中作为标识。 

        // [ 2:使用 CancellationTokenSource  ]
        static CancellationTokenSource Stop;


        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_Load(object sender, EventArgs e)
        {
            button1.Enabled = false;
            button2.Enabled = false;
        }

        private async void button1_Click(object sender, EventArgs e)
        {
            // 初始进度条初始值
            progressBar1.Value = 0;



            //======================================================



            //  [ 1: 使用变量控制进程 ] 。  注意:如果这里调用异步属性Result会报错。   适用简单脚本过程
            // 说明: 如果任务中的标识为true 则跳出循环。  注意:但这并不会终止线程, 这只是跳出了线程的循环而已。
            // Stop = false;        // 停止标识
            // textBox1.Text += tasks1().IsCompleted;  // 因为该方法内部有控件操作,调用该方法会执行该方法。 

            //  [ 2:使用 CancellationTokenSource  ]
            //  说明:该方法和以上似乎差不多, 也是跳出循环。 但是有个问题CancellationTokenSource的值无法恢复默认。 如果使用该类的Cancell方法改变了Token的值, 但却无法恢复为初始。
            // Stop = new CancellationTokenSource();
            // Task t2 = tasks2();                              // 执行任务结果
            // textBox1.Text += "任务是否正常执行:" + AnyDone.IsCompleted + "\r\n";       // 查看任务结果
            // textBox1.Text += "返回任务结果:" + AnyDone.Result + "\r\n";
            // 注意:如果直接使用方法返回,是无法正确获取任务结果的。 如:  textBox1.Text += tasks2().Result.ToString() + "\r\n";



            try
            {
                // 需要获取catch结果需要该方式执行 await  tasks3(Stop.Token);
                Task t3 = tasks3(Stop.Token);
                textBox1.Text += "是否取消了任务:" + t3.IsCanceled + "\r\n";
            }
            catch (OperationCanceledException Ex)
            {
                textBox1.Text += Ex.Message + "\r\n";
            }


            // textbox 自动定位到底部,  注意该语句段需要放在方法的尾部. 因为要作为定位到最后的位置.
            // textBox1.SelectionStart = textBox1.Text.Length;        // 相当于  textBox1.Select(textBox1.Text.Length, 0);
            textBox1.Select(textBox1.Text.Length, 0);
            textBox1.ScrollToCaret();
        }



        /* // [ 1: 使用变量控制进程方法 ]
          async Task tasks1()
          {
              for (int x = 0; x < 101; x++) { if (Stop) { break; } else { await Task.Delay(10); progressBar1.Value = x; } }
          }
          */


        /*        // [ 2:使用 CancellationTokenSource 方法]
                async Task<int> tasks2()
                {
                    int num = 0;
                    for (int x = 0; x < 101; x++)
                    {
                        if (Stop.IsCancellationRequested)
                        { label3.Text = Stop.IsCancellationRequested.ToString(); break; }
                        else
                        { label3.Text = Stop.IsCancellationRequested.ToString(); await Task.Delay(10); progressBar1.Value = x; num = x; }
                    }
                    return num;
                }
        */

        async Task<int> tasks3(CancellationToken tokens)
        {
            int num = 0;
            for (int x = 0; x < 101; x++)
            {
                if (tokens.IsCancellationRequested)
                {
                    tokens.ThrowIfCancellationRequested();    // 触发错误
                    label3.Text = Stop.IsCancellationRequested.ToString();
                }
                else
                {
                    label3.Text = Stop.IsCancellationRequested.ToString();
                    await Task.Delay(10); progressBar1.Value = x; num = x;
                }
            }
            return num;
        }

        private void button2_Click(object sender, EventArgs e)
        {
            // [ 1: 使用变量控制进程方法 ]
            // Stop = true;                   // 停止标识

            // [ 2&3:使用 CancellationTokenSource ]
            Stop.CancelAsync();          // 停止异步

            label3.Text = "True";
        }

        private void button3_Click(object sender, EventArgs e)
        {
            Stop = new CancellationTokenSource();       // 新建CancellationTokenSource对象。 如果使用Cancell方法可以重新生成新对象初始值
            
            button1.Enabled = true;
            button2.Enabled = true;
            label3.Text = "False";
        }


    }
}

## 执行过程

 

posted @ 2024-03-24 08:48  edolf  阅读(12)  评论(0编辑  收藏  举报