• C#中的异步多线程10 BackgroundWorker类


    有些时候,会需要另建一个线程,这个线程在后台持续运行以完成某项工作,并不时地与主线程进行通信。BackgroundWorker类就用于此目的。

    BackgroundWorker类包括

    4个属性:

    1、WorkerReportsProgress

    2、WorkerSupportsCancellation

    3、IsBusy

    4、CancellationPending

    1和2两个属性用于设置后台任务是否可以把它的进度汇报给主线程以及是否支持从主线程取消。可以用IsBusy属性来检查后台任务是否正在运行。

    3个方法:

    1、RunWorkerAsync()

    2、CancelAsync()

    3、ReportProgress()

    3个方法用于初始化行为或改变状态,包括:调用RunWorkerAsync方法获取后台线程并且执行DoWork事件处理程序、调用CancelAsync方法把CancellationPending属性设置为true,Dowork事件处理程序需要检查这个属性来决定是否应该停止处理、DoWork事件处理程序(在后台线程)在希望向主线程汇报进度的时候,调用Report-Progress方法。

    3个事件:

    1、DoWork

    2、ProgressChanged

    3、RunWorkerCompleted

    3个事件用于发送不同的程序事件和状态,需要自己来写事件处理方法来执行适合程序的行为,包括:在后台线程开始的时候触发DoWork、在后台任务汇报状态的时候触发ProgressChanged事件、后台工作线程退出的时候触发RunWorkerCompleted事件。

    要使用BackgroundWorker类对象,DoWork事件时必须的,因为它包含希望在后台线程执行的代码,而另外2个是可选的。

    附加到DoWork事件的处理程序包括希望在后台独立线程上执行的代码。

    1、DoWork的处理程序在独立线程上执行

    2、主线程调用RunWorkerAsync方法的时候触发DoWork事件

    这个后台线程通过调用ReportProgress方法与主线程通信,届时会触发ProgressChanged事件,主线程可以处理附加到ProgressChanged事件上的处理程序。

    附加到RunWorkerCompleted事件的处理程序应该包含后台线程完成DoWork事件处理程序的执行之后需要执行的代码。

    3个事件处理程序都有一个Object对象引用作为第一个参数,以及EventArgs类的特定子类作为第二个参数。

    如果编写了这些事件处理程序并附加到对应的事件,就可以这样使用:

    从创建BackgroundWorker类的对象并且对它进行配置开始:

    1、如果希望工作线程为主线程汇报进度,需要把WorkerReportsProgress属性设置为true

    2、如果希望从主线程取消工作线程,就把WorkerSupportsCancellation属性设置为true

    对象配置好后,可以通过调用RunWorkerAsync方法来启用,它会开启一个后台线程并发起DoWork事件并在后台执行事件处理程序。

    主线程中,尽管后台线程正在运行,但仍然可以继续主线程的处理。

    在主线程中,如果启用了WorkerSupportsCancellation属性,然后可以调用对象的CancelAsync方法,它不会取消后台线程。而是将对象的CancellationPending属性设置为true。运行在后台线程中的DoWork事件处理程序代码需要定期检查CancellationPending属性,来判断是否需要退出。

    同时在后台线程继续执行其计算任务,并且做以下几件事情:

    1、如果WorkerReportsProgress属性是true并且后台线程需要为主线程汇报进度的话,必须调用BackgroundWorker对象的ReportProgress方法,这会触发主线程的ProgressChanged事件,从而运行相应的事件处理程序。

    2、如果WorkerSupportsCancellation属性启用的话,DoWork事件处理程序代码应该经常检查CancellationPending属性来确定是否已经取消了,是的话则退出。

    3、如果后台线程没有取消完成了其处理的话,可以设置DoWorkEventArgs参数的Result字段来返回结果给主线程。

    在后台线程退出的时候会触发RunWorkerCompleted事件,其事件处理程序在主线程上执行,RunWorkerCompletedEventArgs参数可以包含已完成后台线程的一些信息,比如返回值以及线程是否被取消了。

    WPF示例:点击Process按钮将开启后台线程,每半秒向主线程报告一次,并使进度增长10%。

        public partial class MainWindow : Window
        {
            BackgroundWorker bgWorker = new BackgroundWorker();
            public MainWindow()
            {
                InitializeComponent();
                //WorkerReportsProgress-是否汇报后台线程进度给主线程、WorkerSupportsCancellation-是否支持主线程取消后台线程
                bgWorker.WorkerReportsProgress = true;
                bgWorker.WorkerSupportsCancellation = true;
                //DoWork事件是必须的,后台线程执行的时候会触发DoWork事件
                bgWorker.DoWork += DoWork_Handler;
                //ProcessChanged事件会在后台线程向主线程汇报任务状态时触发,可选
                bgWorker.ProgressChanged += ProcessChanged_Handler;
                //RunWorkerCompleted事件会在后台线程退出的时候触发,可选
                bgWorker.RunWorkerCompleted += RunWorkerCompleted_Handler;
    
            }
    
            private void RunWorkerCompleted_Handler(object sender, RunWorkerCompletedEventArgs e)
            {
                processBar.Value = 0;
                if (e.Cancelled)
                    //显示内容和显示窗体名
                    MessageBox.Show("Process was cancelled.", "Process Cancelled");
                else
                    MessageBox.Show("Process completed normally.", "Process Completed");
            }
    
            private void DoWork_Handler(object sender, DoWorkEventArgs e)
            {
                //后台进程运行时触发事件处理程序
                //将worker转换为BackgroundWorker
                BackgroundWorker worker = sender as BackgroundWorker;
                for(int i=1;i<=10;i++)
                {
                    //检查CancellationPending属性是否为true,true则中断后台线程
                    if(worker.CancellationPending)
                    {
                        e.Cancel = true;
                        break;
                    }
                    else
                    {
                        //汇报进度,它会引发ProcessChanged事件,参数是percentProgress
                        worker.ReportProgress(i * 10);
                        Thread.Sleep(500);
                    }
                }
            }
            //在后台线程向主线程汇报状态时触发
            private void ProcessChanged_Handler(object sender, ProgressChangedEventArgs e)
            {
                processBar.Value = e.ProgressPercentage;
            }
    
            private void btnProcess_Click(object sender, RoutedEventArgs e)
            {
                //如果后台线程没有运行,就让他异步运行
                if (!bgWorker.IsBusy)
                    bgWorker.RunWorkerAsync();
            }
    
            private void btnCancel_Click(object sender, RoutedEventArgs e)
            {
                bgWorker.CancelAsync();
            }
        }
        <StackPanel>
            <ProgressBar Name="processBar" Height="20" Width="200" Margin="10"></ProgressBar>
            <Button Name="btnProcess" Width="100" Click="btnProcess_Click" Margin="5">Process</Button>
            <Button Name="btnCancel" Width="100" Click="btnCancel_Click" Margin="5">Cancel</Button>
        </StackPanel>
  • 相关阅读:
    Thread.Join
    WPF几个基础概念的浅显理解
    Vue v-bind指令
    Vue设置路由跳转的两种方法: <router-link :to="..."> 和router.push(...)
    前端上传视频、图片、文件等大文件 组件Plupload使用指南
    vue如何获取并操作DOM元素
    css中border-sizing属性详解和应用
    vue使用axios发送post请求时的坑及解决原理
    vue中的js引入图片,使用require相关问题
    vue 动态添加body背景图片
  • 原文地址:https://www.cnblogs.com/NicolasLiaoran/p/12956175.html
Copyright © 2020-2023  润新知