• thread学习笔记--BackgroundWorker 类


    背景:

    在 WinForms 中,有时要执行耗时的操作,比如统计某个磁盘分区的文件夹或者文件数目,如果分区很大或者文件过多的话,处理不好就会造成“假死”的情况,或者报“线程间操作无效”的异常,或者在该操作未完成之前操作用户界面,会导致用户界面停止响应。

    ----比如现在学习的MES UI中要查询数据量较大的记录显示在Spread中就可以用BackgroundWorker 类!

    解决的方法就是新开一个线程,把耗时的操作放到线程中执行,这样就可以在用户界面上进行其它操作。 如果不借助Thread编程,用户就会感觉界面反映很迟钝。新建线程可以用 Thread 类,可以实现多线程同时操作,简单的可以通过 BackgroundWorker 类实现。 在.Net 2.0中可以通过BackgroundWork非常方便地进行Thread编程,

    大致的步骤是:

    1、调用BackgroundWorker的RunWorkerAsync方法(可以传递参数),它将引发DoWork事件

    2、在DoWork的事件响应代码中调用耗时的操作,是真正的后台处理工作

    3、在耗时操作中判断CancellationPending属性,如果为false则退出

    4、如果要向用户界面发送信息,则调用BackgroundWorker的ReportProgress方法,它将引发ProgressChanged事件(可以将改变通过object类型传递)

    5、在ProgressChanged事件的响应代码中将改变呈现给用户,及运行在主线程中

    6、如果需要取消耗时操作,则调用BackgroundWorker的CancelAsync方法,需要和步骤3一起使用

    命名空间:
    用 BackgroundWorker 类执行耗时的操作
    BackgroundWorker 类在 System.ComponentModel 命名空间下。
    VS 的工具箱时有一个 BackgroundWorker 组件,就是这个类。

     属性、方法和事件:
        重要属性:
        1、CancellationPending            

    获取一个值,指示应用程序是否已请求取消后台操作。通过在DoWork事件中判断CancellationPending属性可以认定是否需要取消后台操作(也就是结束线程);
        2、IsBusy                          

    获取一个值,指示 BackgroundWorker 是否正在运行异步操作。程序中使用IsBusy属性用来确定后台操作是否正在使用中;
        3、WorkerReportsProgress          

    获取或设置一个值,该值指示BackgroundWorker能否报告进度更新
        4、WorkerSupportsCancellation      

    获取或设置一个值,该值指示 BackgroundWorker 是否支持异步取消。设置WorkerSupportsCancellation为true使得程序可以调用CancelAsync方法提交终止挂起的后台操作的请求;
        重要方法:
        1、CancelAsync         请求取消挂起的后台操作
        2、RunWorkerAsync      开始执行后台操作
        3、ReportProgress      引发ProgressChanged事件  
        重要事件:
        1、DoWork              调用 RunWorkerAsync 时发生
        2、ProgressChanged     调用 ReportProgress 时发生
        3、RunWorkerCompleted  当后台操作已完成、被取消或引发异常时发生

    生命周期中的参数传递:

    在整个生命周期内发生了3次重要的参数传递过程:
        参数传递1:此次的参数传递是将RunWorkerAsync(Object)中的Object传递到DoWork事件的DoWorkEventArgs.Argument,由于在这里只有一个参数可以传递,所以在实际应用往封装一个类,将整个实例化的类作为RunWorkerAsync的Object传递到DoWorkEventArgs.Argument;
        参数传递2:此次是将程序运行进度传递给ProgressChanged事件,实际使用中往往使用给方法和事件更新进度条或者日志信息;
        参数传递3:在DoWork事件结束之前,将后台线程产生的结果数据赋给DoWorkEventArgs.Result一边在RunWorkerCompleted事件中调用RunWorkerCompletedEventArgs.Result属性取得后台线程产生的结果。
        看到DoWork事件是在后台线程中运行的,所以在该事件中不能够操作用户界面的内容,如果需要更新用户界面,可以使用ProgressChanged事件及RunWorkCompleted事件来实现。 

    源代码:

    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.Data;
    using System.Drawing;
    using System.Linq;
    using System.Text;
    using System.Windows.Forms;
    
    namespace WindowsFormsApp_BackGroundWorker
    {
        public partial class Form1 : Form
        {
            public Form1()
            {
                InitializeComponent();
    
                //设置能够报告进度更新
                //设置能够支持异步取消
                backgroundWorker1.WorkerReportsProgress = true;
                backgroundWorker1.WorkerSupportsCancellation = true;
            }
    
                 //在designer里的属性设计器里直接双击就添加了对backgroundWorker1的ProgressChanged的事件处理程序
                //this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
                //this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
                //this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);
    
    
            //由ReportProgress方法触发,通过响应消息,来处理界面的显示工作
            private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
            {
                //获取异步操作进度百分比,主线程
                this.progressBar1.Value = e.ProgressPercentage;
                this.label1.Text = e.UserState.ToString();
                this.label1.Update();
    
            }
    
    
            //后台工作完成时引发的事件,可以在此事件处理程序里面写进行后续的处理工作,比如提示
            private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
            {
                //MessageBox.Show("计算终于完成了!");
                if (!e.Cancelled && e.Error == null)
                {
                    MessageBox.Show("处理完成了!" + e.Result);
                }
                else
                {
                    MessageBox.Show("后台线程被取消或发生异常!");
                }
            }
    
    
            //此事件由开始按钮里的调用RunWorkerAsync方法引发
            //这里就是后台进程开始的地方,调用工作函数的地方,也可以把现有的处理函数写在这里
            private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
            {
               // Countwork(this.backgroundWorker1);
                Countwork(backgroundWorker1);
            }
    
            //后台处理函数,真正的处理工作
            private bool Countwork(BackgroundWorker bw)
            {
                int n = 10000;
                for (int i = 0; i <= n; i++)
                {
                    //判断用户是否执行了取消后台操作,是的话显示返回
                    if (bw.CancellationPending)
                    {
                        bw.ReportProgress(i,string.Format("当前操作值是{0},操作被用户申请中断",i));
                        return false;
     
                    }
                    //ReportProgress函数的作用是,向主线程报告处理进度。折算成百分比,或者把进度条的最大值设置为10000
                    bw.ReportProgress(i,string.Format("当前值是{0}",i));
                }
                return true;
     
            }
    
            private void button_Start_Click(object sender, EventArgs e)
            {
                //判断是否在进行异步操作,应对用户多次点击开始按钮
                if(this.backgroundWorker1.IsBusy)
                {
                    return;
                }
    
                //触发DOWORK事件,实际就是让后台工作开始
                this.backgroundWorker1.RunWorkerAsync();
            }
    
            //不太好用...
            private void button_Cancel_Click(object sender, EventArgs e)
            {
                this.backgroundWorker1.CancelAsync();
                this.backgroundWorker1.Dispose();//释放资源
            }
    
            private void button_Exit_Click(object sender, EventArgs e)
            {
                this.Close();
            }
    
    
    
    
        }
    }

    运行截图:

    以上,本人的学习总结,优秀BLOG参考:

    http://blog.itpub.net/23109131/viewspace-670314/

    http://blog.163.com/j_yd168/blog/static/4967972820092114269195/   c# BackGroundWorker 多线程操作的小例子

     

  • 相关阅读:
    Java数组的使用
    Java的栈堆以及数组两种不同类型的定义
    Java数组声明的创建
    JAVA递归
    Java可变参数
    Java方法(类--------对象--------方法)
    html块元素和内联元素的区别
    HTML基础介绍
    CSS网页美化元素属性介绍
    ArrayList类的remove(Object o)方法简述
  • 原文地址:https://www.cnblogs.com/ammy714926/p/4549057.html
Copyright © 2020-2023  润新知