C# GUI_Async_await异步报告

// .net8环境 Winform
namespace GUI_Async_await异步报告_供参考_
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
            progressBar1.Value = 0;
            progressBar2.Value = 0;
            progressBar3.Value = 0;                         // 进度条 恢复初始值.  不然Value的值 一直是100.
            sync();     // 同步方法
        }

        private async void button2_Click(object sender, EventArgs e)   // 注意: 使用 async 的方法需要在 async 方法内调用.
        {
            progressBar1.Value = 0;
            progressBar2.Value = 0;
            progressBar3.Value = 0;                         // 进度条 恢复初始值.  不然Value的值 一直是100.
            progressBar2.Value = await Async();     //  返回执行结果, 注意, 并不是执行过程.   这样的异步方法不会卡在UI界面.   这样的方法适合在后台处理, 直到处理完成再报告结果.
        }

        private async void button3_Click(object sender, EventArgs e)
        {
            progressBar1.Value = 0;
            progressBar2.Value = 0;
            progressBar3.Value = 0;                         // 进度条 恢复初始值.  不然Value的值 一直是100.
            await CallBack();      // 执行异步过程
            
        }

        private async void button4_Click(object sender, EventArgs e)
        {
            progressBar1.Value = 0;
            progressBar2.Value = 0;
            progressBar3.Value = 0;                         // 进度条 恢复初始值.  不然Value的值 一直是100.
            await Step_Report();    // 阶梯式进度条.    如果需要快速调用异步过程方法, 可以试着参考该方法.
        }

        async void More_Async()  // 多个异步方法组合处理
        {
            int[] ints = await Task.WhenAll(Async(), Async());                  // 返回一组任务组, 如果任务组都完成则都返回
            Task<int> Int = await Task.WhenAny(Async(), Async());       // 返回优先完成的任务
            // 注意:如果直接使用方法返回,是无法正确获取任务结果的。 如:  textBox1.Text += Async().IsCompleted;
        }

        // 同步方法
        void sync()
        {
            for (int x = 0; x < 101; x++) { Thread.Sleep(100); progressBar1.Value = x; }
        }

        // 异步方法
        // 如果需要了解到Task方法是否完成, 就需要Task的返回结果.
        // 当然也可以 async void 不需要返回值, 但是这样就不知道执行结果了. 还是根据需求设计.
        async Task<int> Async()
        {
            int result = 0;
            await Task.Run(() =>
            {
                for (int x = 0; x < 101; x++)
                {
                    Thread.Sleep(10);     // 等待0.1秒
                    result = x;                 // 需要知道Task是否完成所以需要一个值来返回.
                }
            });
            return result;                    // 返回结果 

        }



        
        // 异步过程, 会将后台处理的过程显示在UI界面上, 而不影响UI.
        // 需要使用到 IProgress 泛型接口 和 Progress 泛型类,
        async Task Async_Timeout(IProgress<int> progress)        // 这里Task没有指定类型, 默认为null.
        /*  需要注意的是,IProgress<T>.Report 方法可以是异步的。这意味着真正报告进度之前,Async_Timeout 方法会继续运行。
         *  基于这个原因,最好把 T 定义为一个不可变类型,或者至少是值类型。
         *  如果 T 是一个可变的引用类型,就必须在每次调用 IProgress<T>.Report 时, 创建一个单独的副本。*/

        {
            for (int x = 0; x < 101; x++)
            {
                await Task.Delay(10);   // Task.Delay 拥有返回值
                progress.Report(x);      // progress 只有一个Reprot报告的方法.           
            }
        }

        async Task CallBack()
        {
            var progress = new Progress<int>();   // 使用 Progress 泛型类
            /*  Progress<T> 会在创建时捕获当前上下文,并且在这个上下文中调用回调函数。这意味着,
             *  如果在 UI 线程中创建了 Progress<T>,就能在 Progress< T > 的回调函数中更新 UI,即使异
             *  步方法是在后台线程中调用 Report 的。*/

            progress.ProgressChanged += (sender, y) => { progressBar3.Value = y; change_progress(y); };  //  实例化的 Progress 只有一个事件方法, (sender, y) 括号内两个的参数名可以自定义, 但是传参的是 第二个参数
            // var progress = new Progress<int>(change_progress);          // 如果ProgressChanged 太麻烦, 可以使用构造Progress函数填入一个方法即可, 这个方法不需要填入参数, 因为该参数默认指定为Async_Progress的返回值, 但是只能指定一个方法
            await Async_Timeout(progress);
        }

        void change_progress(int y)  // 仅能被CallBack方法调用.
        {
            progressBar1.Value = y;
            progressBar2.Value = y;
        }





        async Task Step_Report()    // 阶梯式进度条
        {
            for (int x2 = 0; x2 < 101; x2 += 20)
            {
                progressBar3.Value = x2;
                if (x2 >= 100) { break; }         // 最后进度条完成 则所有进度条都完成
                for (int x1 = 0; x1 < 101; x1 += 5)
                {
                    progressBar2.Value = x1;
                    for (int x = 0; x < 101; x += 10) { await Task.Delay(10); progressBar1.Value = x; }
                }

            }
        }


    }
}

 ## 执行过程

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