.net开发中用BackgroundWorker实现多线程

背景介绍:

在做程序的过程中,我们很可能遇到这样的情况:当我们执行一个比较耗时的操作,即界面加载数据量略大的时,在该操作未完成之前再去操作界面,就会出现停止响应的情况,这称为界面假死状态,那一个小圆圈转呀转的,想必大家看着就头疼。当然这是一个非常影响用户体验度的地方。

怎么做出一个能够及时响应的用户界面呢?多线程操作。

引入BackgroundWorker组件:

BackgroundWorker是·net里用来执行多线程任务的控件,它允许编程者在一个单独的线程上执行一些操作。

常用方法

1.RunWorkerAsync 开始执行后台操作。引发 DoWork 事件

2.CancelAsync 请求取消挂起的后台操作。

注意:这个方法是将 CancellationPending 属性设置为 true,并不会终止后台操作。在后台操作中要检查 CancellationPending 属性,来决定是否要继续执行耗时的操作。

3.ReportProgress 引发 ProgressChanged 事件。

常用属性

1.CancellationPending 指示应用程序是否已请求取消后台操作。只读属性,默认为 false,当执行了 CancelAsync 方法后,值为 true。

2.WorkerSupportsCancellation 指示是否支持异步取消。要执行 CancelAsync 方法,需要先设置该属性为 true。

3.WorkerReportsProgress 指示是否能报告进度。要执行 ReportProgress 方法,需要先设置该属性为 true。

常用事件

1.DoWork 调用 RunWorkerAsync 方法时发生。

2.RunWorkerCompleted 后台操作已完成、被取消或引发异常时发生。

3.ProgressChanged 调用 ReportProgress 方法时发生。

注意:在 DoWork 事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和RunWorkerCompleted 事件与用户界面进行通信。

如果想在 DoWork 事件处理程序中和用户界面的控件通信,可在用 ReportProgress 方法。ReportProgress(int percentProgress, object userState),可以传递一个对象。

ProgressChanged 事件可以从参数ProgressChangedEventArgs 类的UserState 属性得到这个信息对象。这个事件也可以实现进度条功能,把任务的进度实时呈现给用户。

简单的程序用BackgroundWorker 比 Thread 方便,Thread中和用户界面上的控件通信比较麻烦,需要用委托来调用控件的 Invoke 或BeginInvoke 方法,没有 BackgroundWorker 方便。

BackgroundWorkerDemo

namespace BackgroundWorkerTest
{
    public partial class Form1 : Form
    {
        public Form1()
        {
            InitializeComponent();
            backgroundWorker1.WorkerReportsProgress = true;//报告完成进度
            backgroundWorker1.WorkerSupportsCancellation = true;//允许用户终止后台线程
        }
        //开始按钮
        private void button1_Click(object sender, EventArgs e)
        {
            if (!backgroundWorker1.IsBusy )//判断backgroundWorker1是否正在运行异步操作
            {
                //backgroundWorker1.RunWorkerAsync();
                backgroundWorker1.RunWorkerAsync(1000);//开始执行后台操作,调用DoWork事件
            }
        }
      
        //DoWork事件声明要执行的耗时操作
        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            e.Result = ListNumber(backgroundWorker1, e);//运算结果保存在e.Result中
        }
 
        bool ListNumber(object sender, DoWorkEventArgs e)
        {
            int num=(int)e.Argument;//接收传入的参数
            for (int i = 1; i <= num; i++)
            {
                if (backgroundWorker1.CancellationPending)//判断是否请求了取消后台操作
                {
                    e.Cancel=true;
                    return false;
                }
                //backgroundWorker1.ReportProgress(i * 100 / num);
                backgroundWorker1.ReportProgress(i * 100 / num,i);//报告完成进度
                Thread.Sleep(0);//后台线程交出时间片
            }
            return true;
        }
 
        private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
        {
            //将完成进度数据传给进度条
            progressBar1.Value = e.ProgressPercentage;
            label1.Text = e.ProgressPercentage + "%";
            //将中间计算结果在ListBox控件中显示出来
            listBox1.Items.Add(e.UserState);
        }
 
     Private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
     {
          if (!e.Cancelled && e.Error==null)
          {
              MessageBox.Show("处理完成了吗?  " + e.Result);
          }
          else//如果取消后台线程或发生了异常
          {
              MessageBox.Show("处理完成了吗?  false");
          }
      }
 
        //取消按钮
        private void button2_Click(object sender, EventArgs e)
        {
            if (backgroundWorker1.WorkerSupportsCancellation==true)
            {
                backgroundWorker1.CancelAsync();//取消后台操作
                backgroundWorker1.Dispose();//释放资源
            }
        }
    }
}

总结:

使用backgroundWorker实现多线程大致的步骤是:

1、 绑定线程,设置属性

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

3、声明DoWork事件的委托方法,在后台执行耗时的操作

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

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

6、在ProgressChanged事件的响应代码中将改变呈现给用户,类似进度条。

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

总的来说就是用backgroundWorker组件来新建一个线程,把耗时的部分放到这个线程中在后台进行处理。这样就不会影响界面的正常使用。举个通俗的例子,在我们打开一个网页的时候,先加载完的总是文字,然后图片在慢慢出现。这就是线程的应用,网页打开的时候先呈现出文字,供用户浏览,然后把加载图片放到一个单独的线程中,异步的在后台执行,执行完毕后把图片呈现出来。

这样就避免了一打开界面就加载大量信息,而造成的界面假死状态,大大提高了用户体验度。

时间: 2024-11-09 00:58:38

.net开发中用BackgroundWorker实现多线程的相关文章

测试-Android开发中用VideoView运行时出现该视频无法播放

问题描述 Android开发中用VideoView运行时出现该视频无法播放 package com.example.myvideo; import java.io.File; import android.app.Activity; import android.media.MediaPlayer; import android.media.MediaPlayer.OnErrorListener; import android.media.MediaPlayer.OnPreparedListen

线程-安卓开发中用new Thread()的困惑?

问题描述 安卓开发中用new Thread()的困惑? 用listview从服务端取数据的方法用new Thread()并且用SystemClock.sleep延迟几秒,等数据准备完后再刷新listview.不理解为什么要另开一个线程和要延迟,如果在主线程中取数据会有什么问题? 解决方案 如果在主线程中进行网络请求,会造成ANR异常!同时从安卓版本高级版本,貌似是11开始,不能在主线程中进行网络请求,否则直接报异常!所以不能在主线程进行网络请求! 所以,一般进行网络请求都要新开一个线程进行访问!

app上线后出现BUG怎么处理?开发中用什么方法预防这类问题发生? 跪求大神解答!

问题描述 app上线后出现BUG怎么处理?开发中用什么方法预防这类问题发生? 跪求大神解答! app上线后出现BUG怎么处理?开发中用什么方法预防这类问题发生? 跪求大神解答! 解决方案 出现bug就发布新的版本,客户端自动检查你的服务器,自动下载升级.另外开发过程中注意测试,减少bug

C#编程语言,委托在一般公司开发中用的多么?

问题描述 C#编程语言,委托在一般公司开发中用的多么? C#编程语言,委托在一般公司开发中用的多么?我看好像基本不用它.有没有必要花时间学? 解决方案 不同的人情况不同.既然你看到它基本用不上,说明你去工作的公司里的确是不用的.用的上的公司也不要你,你也不用操心.

php项目开发中用到的快速排序算法分析_php技巧

本文实例讲述了php项目开发中用到的快速排序算法.分享给大家供大家参考,具体如下: 实际上在,做web开发,比较少遇到使用一些算法之类的,毕竟不是做搜索引擎,也不是写底层(比如写个类似于mysql这样的数据库,里面需要自己实现排序算法),另外,每种语言,比如java,php都或多或少已经封装好排序函数给程序员使用.比如有个共识,大家做web开发的基本都明白,业务逻辑多比较简单,不是很复杂的业务逻辑.我们作为web开发的程序员,基本是是web架构,对数据库增删查改数据,然后把数据展示在页面中,大多

ios开发中用到FaceRecognizer遇到的问题

问题描述 ios开发中用到FaceRecognizer遇到的问题 请问遇到这个问题如何解决? 求大神帮帮忙

Android开发仿下载助手多线程下载及原理

仿下载助手界面效果 开发仿下载助手多线程下载及原理-android 双开助手原理"> 线程池 ThreadPoolExecutor 在下面介绍实现下载原理的时候,我想尝试倒着来说,这样是否好理解一点? 我们都知道,下载助手,比如360, 百度的 手机助手,下载APP 的时候 ,都可以同时下载多个,所以,下载肯定是多线程的,所以我们就需要一个线程工具类 来管理我们的线程,这个工具类的核心,就是 线程池. 线程池ThreadPoolExecutor ,先简单学习下这个线程池的使用  /**  

Android开发中用相机拍照后图片裁剪的实例及源码

其实Android提供Intent让我们打开系统的相机,但是系统相机跟自己app风格不搭,而且用起来体验不好.所以我使用了SDK提供的camera API自定义了一个相机,并且在相机界面上面添加了参考线,有助于用户将题目拍正,提高ocr的识别率. 1.绘制参考线的代码 public class ReferenceLine extends View {     private Paint mLinePaint;     public ReferenceLine(Context context) {

Web开发中用sql语句完成分页的特效方法

这篇文章以jsp/asp为例,简要介绍了Web开发中一种用sql语句完成分页的高效率方法. 一.Jsp方法如下: **********************<%@ page language=java import=java.util.*,java.sql.* %><%@ page contentType=text/html;charset=gb2312%><jsp:useBean id=cn scope=page class=myConnection.Conn />