BackgroundWorker的妙用

来源:互联网 发布:icloud会备份哪些数据 编辑:程序博客网 时间:2024/06/09 23:11
需求:后台不间断地进行某种工作,当获得特定结果时弹出窗体进行提示,而工作继续进行。那我的第一反应就是,该工作应放到后台线程中执行,条件满足时创建/显示提示窗体就行啦。代码如下:==========================Work.cs==============================using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.ComponentModel;namespace ThreadTest{ public class Work { Thread thd; private static int count = 0; public Work() { thd = new Thread(new ThreadStart(thdDoWork)); thd.Name = "NewThread"; } WarningForm wf;//提示窗体 private void thdDoWork()//后台工作 { while (true) { if ((count++ % 10) == 0) { wf = new WarningForm();//创建并显示提示窗体 wf.Show();//将窗体显示为非模式对话框 } Thread.Sleep(600); } } public void ThdStart() { thd.Start(); } }}==========================Work.cs==============================同时呢,在WarningForm的构造函数中添加:Console.WriteLine("WarningForm Created in : " + Thread.CurrentThread.Name);这样我们就能够清楚的看到WarningForm是在哪一个线程中被创建显示的。Debug,弹出提示窗口,而且后台工作没有停止,但是提示窗口没有响应,后台输出“WarningForm Created in : NewThread”。我分析这是因为我们把提示窗体显示为了非模式的,而后台线程显示窗体后继续执行,并没有维护对提示窗体界面的响应,因此发生了以上现象。那我们把"wf.Show()"改为"wf.ShowDialog()"再试一下:Debug,弹出提示窗口,界面没有死掉,后台输出"WarningForm Created in : NewThread",但是后台的工作却停止了。这是因为ShowDialog()将窗体显示为模式的,也就是说该窗体的显示阻塞掉了当前线程的运行。这样看来,把提示窗体的显示放到后台线程中是不行的,那么,当后台线程需要显示窗体时,如何在主线程中捕获这种消息呢?哈,这位客官运气真好,BackgroundWorker的ReportProgress(int percentProgress, object userState)方法最适合解决这个问题了。我们可以在主线程中注册BackgroundWorker的ProgressChanged事件,当BackgroundWorker的对象调用ReportProgress()时,注册到ProgressChanged事件的方法就会在主线程中执行,对后台线程的运行没有任何影响,然后提示窗体是要显示为模式的还是非模式的就看情况啦!我们修改Work.cs如下:==========================Work.cs==============================using System;using System.Collections.Generic;using System.Linq;using System.Text;using System.Threading;using System.ComponentModel;namespace ThreadTest{ public class Work { public BackgroundWorker bg; private static int count = 0; public Work() { bg = new BackgroundWorker(); } private void bgDoWork(object sender, DoWorkEventArgs e) { Thread.CurrentThread.Name = "BgWorker";//修改后台线程的名字 while (true) { if ((count++ % 10) == 0) bg.ReportProgress(count);//激活事件 Thread.Sleep(500); } } public void BgStart() { bg.WorkerReportsProgress = true; bg.DoWork += new DoWorkEventHandler(bgDoWork); bg.RunWorkerAsync(); } }}==========================Work.cs==============================同时在Form1.cs中如下编写:========================Form1.cs片段============================ WarningForm wf; public Form1() { InitializeComponent(); Thread.CurrentThread.Name = "MainThread";//修改主线程名字 } private void button3_Click(object sender, EventArgs e) { //work为Work的对象 work.bg.ProgressChanged += new ProgressChangedEventHandler(bg_ProgressChanged);//注册这一事件 work.BgStart(); } private void bg_ProgressChanged(object sender, ProgressChangedEventArgs e) { //事件发生时显示提示窗体 wf = new WarningForm(); wf.Show(); //wf.ShowDialog(); }========================Form1.cs片段============================Debug,输出"WarningForm Created in : MainThread",可以看到窗体是在主线程中创建显示的。而无论提示窗体是模式的还是非模式的,一切均能正常运行,到此,我们就实现了要求的功能哈哈!另外,请注意ReportProgress(int percentProgress, object userState),它第二个参数是object类型的,再加上如前所述的特性使得BackgroundWorker与界面进行通信的时非常的方便,我们在更新控件的时候可以用它。而如果使用Thread对象的话,则需要通过委托来调用控件的Invoke或者BeginInvoke方法,麻烦的多。但是我想后者肯定具有一些独特的优点,目前我还不知道,求指点。。