程序员人生 网站导航

BackgroundWorker 实现多线程操作

栏目:php教程时间:2014-12-20 09:07:46

背景介绍:

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

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

       引入BackgroundWorker组件:

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

经常使用方法

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),可以传递1个对象。

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

 

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

 

BackgroundWorker Demo

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、调用BackgroundWorkerRunWorkerAsync方法(可以传递参数),它将调用DoWork事件

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

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

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

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

7、如果需要取消耗时操作,则调用BackgroundWorkerCancelAsync方法,需要和步骤31起使用

 

    总的来讲就是用backgroundWorker组件来新建1个线程,把耗时的部份放到这个线程中在后台进行处理。这样就不会影响界面的正常使用。举个通俗的例子,在我们打开1个网页的时候,先加载完的总是文字,然后图片在渐渐出现。这就是线程的利用,网页打开的时候先显现出文字,供用户阅读,然后把加载图片放到1个单独的线程中,异步的在后台履行,履行终了后把图片显现出来。

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

 

 

线程处理这块不熟,希望大家指导。


------分隔线----------------------------
------分隔线----------------------------

最新技术推荐