zoukankan      html  css  js  c++  java
  • C# 异步调用中 BackgroundWorker的使用

    一、概述   

      1、BackgroundWorker 类允许您在单独的专用线程上运行操作,在界面上报告进度,接受界面的控制信号,返回运算结果。

         2、BackgroundWorker 的DoWork代码运行在非UI线程之上,BackgroundWorker 不跨 AppDomain 边界进行封送处理。

      3、BackgroundWorker 是基于事件的异步编程模式EAP的复杂实现。

    二、BackgroundWorker 配置

    1、初始化BackgroundWorker 

      主要需要对BackgroundWorker 绑定一下三个事件:  

    • 开始工作的事件:DoWork——非UI线程执行,不可操作界面控件对象
    • 完成工作的事件:RunWorkerCompleted——UI线程执行
    • 工作中刷新的事件:ProgressChanged——UI线程执行
         public static void BackgroundWorker1_Init()
            {
                BackgroundWorker backgroundWorker1 = new BackgroundWorker();
                backgroundWorker1.WorkerReportsProgress = true;//能否报告进度更新。
                backgroundWorker1.WorkerSupportsCancellation = true;//是否支持异步取消
                //绑定事件
                backgroundWorker1.DoWork += new DoWorkEventHandler(BackgroundWorker1_DoWork);
                backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorker1_ProgressChanged);
                backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorker1_RunWorkerCompleted);
    
                //启动BackgroundWorker
                if (backgroundWorker1.IsBusy != true)//判断BackgroundWorker 是否正在运行异步操作。
                {
                    backgroundWorker1.RunWorkerAsync("object argument");//启动异步操作,有两种重载(有参和无参),将触发BackgroundWorker.DoWork事件
                }
            }

    2、DoWork开始事件

         /// <summary>
            /// 句柄sender指向的就是该BackgroundWorker。
            /// e.Argument 获取异步操作参数的值  
            /// e.Cancel 是否应该取消事件
            /// e.Result  获取或设置异步操作结果的值(在RunWorkerCompleted事件可能会使用到)
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                object value = e.Argument;//获取RunWorkerAsync(object argument)传入的值
                BackgroundWorker worker = sender as BackgroundWorker;
    
                for (int i = 1; i <= 10; i++)
                {
                    if (worker.CancellationPending == true)//在耗时操作中判断CancellationPending属性,如果为true则退出
                    {
                        e.Cancel = true;
                        break;
                    }
                    else
                    {
                        // 执行耗时操作
                        System.Threading.Thread.Sleep(1000);
                        worker.ReportProgress(i * 10, "Object userState");// 将触发BackgroundWorker.ProgressChanged事件,向ProgressChanged报告进度
                    }
                }
                e.Result = "结束";
            }

    3、RunWorkerCompleted完成事件

      当DoWork事件处理完成之后,将会触发该事件处理工作结果。事件可根据传入的参数e来区分工作是中止或完成。

         /// <summary>
            /// e.Cancelled指示异步操作是否已被取消
            /// e.Error 指示异步操作期间发生的错误
            /// e.Result 获取异步操作结果的值,即DoWork事件中,Result设置的值。    
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                //判断是否用户手动取消,若程序要支持此处功能,需要程序中有cancel的动作,并在该动作中将e.cancel置为true
                if (e.Cancelled == true)
                {
                    //添加用户手动取消的动作,并在标签控件中进行提示  
                    Console.WriteLine($"操作已经被取消!");
                }
                //判断是否由错误造成意外中止
                else if (e.Error != null)
                {
                    //若发生错误,在标签控件中显示错误信息
                    Console.WriteLine($"操作发生错误!");
                }
                //判断是否正常结束
                else
                {
                    //添加正常结束之后的收尾动作,并在标签控件中进行提示
                    Console.WriteLine($"执行结果:{e.Result.ToString()}!");
                }
            }

    4、ProgressChanged刷新事件

      更新进度条的进度,此处也可以加入用户在过程中需要实时刷新的内容

         /// <summary>
            /// 进度刷新
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                //接收ReportProgress方法传递过来的userState
                string state = (string)e.UserState;
                //e.ProgressPercentage  获取异步操作进度的百分比
                Console.WriteLine($"进度:{e.ProgressPercentage.ToString() + "%"};状态:{state}");
            }

    5、取消BackgroundWorker

      取消BackgroundWorker 需要在DoWork中循环检查BackgroundWorker.CancellationPending是否为true。

    //终止
    private void  BackgroundWorker1_End()
    {
        if (backgroundWorker1.WorkerSupportsCancellation == true)
        {
            // Cancel the asynchronous operation.
            backgroundWorker1.CancelAsync(); //请求取消挂起的后台操作。调用该方法将使BackgroundWorker.CancellationPending属性设置为True。 
        }
    }
     

    三、完整的代码

    using System;
    using System.ComponentModel;
    
    namespace BackgroundWorkerDemo
    {
        public class BackgroundWorkerInit
        {
            public static void BackgroundWorker1_Init()
            {
                BackgroundWorker backgroundWorker1 = new BackgroundWorker();
                backgroundWorker1.WorkerReportsProgress = true;//能否报告进度更新。
                backgroundWorker1.WorkerSupportsCancellation = true;//是否支持异步取消
                //绑定事件
                backgroundWorker1.DoWork += new DoWorkEventHandler(BackgroundWorker1_DoWork);
                backgroundWorker1.ProgressChanged += new ProgressChangedEventHandler(BackgroundWorker1_ProgressChanged);
                backgroundWorker1.RunWorkerCompleted += new RunWorkerCompletedEventHandler(BackgroundWorker1_RunWorkerCompleted);
    
                //启动BackgroundWorker
                if (backgroundWorker1.IsBusy != true)//判断BackgroundWorker 是否正在运行异步操作。
                {
                    backgroundWorker1.RunWorkerAsync("object argument");//启动异步操作,有两种重载(有参和无参),将触发BackgroundWorker.DoWork事件
                }
            }
    
            /// <summary>
            /// 句柄sender指向的就是该BackgroundWorker。
            /// e.Argument 获取异步操作参数的值  
            /// e.Cancel 是否应该取消事件
            /// e.Result  获取或设置异步操作结果的值(在RunWorkerCompleted事件可能会使用到)
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
                object value = e.Argument;//获取RunWorkerAsync(object argument)传入的值
                BackgroundWorker worker = sender as BackgroundWorker;
    
                for (int i = 1; i <= 10; i++)
                {
                    if (worker.CancellationPending == true)//在耗时操作中判断CancellationPending属性,如果为true则退出
                    {
                        e.Cancel = true;
                        break;
                    }
                    else
                    {
                        // 执行耗时操作
                        System.Threading.Thread.Sleep(1000);
                        worker.ReportProgress(i * 10, "Object userState");// 将触发BackgroundWorker.ProgressChanged事件,向ProgressChanged报告进度
                    }
                }
                e.Result = "结束";
            }
    
    
            /// <summary>
            /// e.Cancelled指示异步操作是否已被取消
            /// e.Error 指示异步操作期间发生的错误
            /// e.Result 获取异步操作结果的值,即DoWork事件中,Result设置的值。    
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                //判断是否用户手动取消,若程序要支持此处功能,需要程序中有cancel的动作,并在该动作中将e.cancel置为true
                if (e.Cancelled == true)
                {
                    //添加用户手动取消的动作,并在标签控件中进行提示  
                    Console.WriteLine($"操作已经被取消!");
                }
                //判断是否由错误造成意外中止
                else if (e.Error != null)
                {
                    //若发生错误,在标签控件中显示错误信息
                    Console.WriteLine($"操作发生错误!");
                }
                //判断是否正常结束
                else
                {
                    //添加正常结束之后的收尾动作,并在标签控件中进行提示
                    Console.WriteLine($"执行结果:{e.Result.ToString()}!");
                }
            }
    
    
            /// <summary>
            /// 进度刷新
            /// </summary>
            /// <param name="sender"></param>
            /// <param name="e"></param>
            private static void BackgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                //接收ReportProgress方法传递过来的userState
                string state = (string)e.UserState;
                //e.ProgressPercentage  获取异步操作进度的百分比
                Console.WriteLine($"进度:{e.ProgressPercentage.ToString() + "%"};状态:{state}");
            }
        }
    }
    View Code
    using System;
    
    namespace BackgroundWorkerDemo
    {
        class Program
        {
            static void Main(string[] args)
            {
                BackgroundWorkerInit.BackgroundWorker1_Init();
                Console.ReadKey();
            }
        }
    }

    执行结果:

  • 相关阅读:
    最大回文子串
    求数组中的最大连续子序列和
    如何在10亿数中找出前1000大的数
    给定一个字符串,最多删除一个字符,判断能够构成回文字符串
    HashMap(数组+链表+红黑树)、HashTable、TreeMap
    【转】jmeter如何设置登录接口只调用一次以及遇到的问题:cookie参数放在消息头headers里面
    Kafka命令行操作
    git上无法push代码解决办法
    【转】Jenkins集成Docker镜像实现自动发布
    awk命令总结
  • 原文地址:https://www.cnblogs.com/qtiger/p/13495325.html
Copyright © 2011-2022 走看看