凡是WinForm的应用程序,如果他执行了一个的非常冗长的处理操作(比如文件查询),它在执行时会锁定用户界面,虽然主活动窗口 一直在运行,但用户无法与程序交互,无法移动窗体或改变窗体大小,所以用户感觉很不爽。如何做才能使得这个程序有响应。答案就是在后台线程中执行这个操作。
在这里已经有了多种方法来做这个事情:
(一)委托异步调用
将具体耗时的操作作为一个委托,并用BeginInvoke来异步执行这个委托(Invoke是同步调用),并且可以为这个操作传入参数并且通过EndInvoke方法获得返回返回值。
(二)使用ThreadPool
新建.net FrameWork中自带的WaitCallback委托,然后放到线程池中运行ThreadPool.QueueUserWorkItem( callback ); 根据WaitCallback委托的定义,可以传入一个object类型的参数。
但是不能精确的控制线程池中的线程。
(三)使用Thread
和ThreadPool相比,使用Thread的开销会比较大。但是它有它的优势,使用 Thread 类可以显式管理线程。只要有可能,就应该使用 ThreadPool 类来创建线程。然而,在一些情况下,您还是需要创建并管理您自己的线程,而不是使用 ThreadPool 类。在.net 2.0 中,提供了一个新的委托 ParameterizedThreadStart 支持启动一个线程并传入参数,这是对原来的ThreadStart委托的改进。
说了这么多还没有说到今天的主角BackgroundWorker,他也是一个在2.0中新增的类,可以用于启动后台线程,并在后台计算结束后调用主线程的方法.可以看出同样的功能使用委托的异步调用也可以实现,只是使用BackgroundWorker的话会更加的简便快捷,可以节省开发时间,并把你从创建自己的委托以及对它们的调用中解救出来。真是这样的吗看看下面这个例子。其实我也是从101Samples中看到的例子。
先看看BackgroundWorker中的主要概念。
BackGroundWorker是微软提供的封装好了的,非常实用的控件,我们可以在控件中将其拖到Winform之中,然后简单的系统生成代码式的编辑事件处理。
以下是,比较经典且简单的实用,后面的一篇较复杂,不使用微软控件式,自行生成,并传递参数给多线程,并通过多线程更新主线程的多处UI,线程没操作完一笔记录,则报告进度,更新UI。
下图是微软提供给我们的控件,拖到Winform中
我们可以看到有如下三个事件:
1、线程执行的动作,一般用于复杂操作,DoWork
2、线程进度改变,进度条变化
3、线程执行完,这时候,又回到主线程执行了,可以访问主线程中的UI,操作主线程的UI
下列是最基本的核心代码,只给出最核心部分,其他简单部分省略。
如果我主线程要传递参数,以及多线程如何接受参数,可以参考多线程按F12去查看微软给出的操作,一般较多的是DataTable类型的,这个也是最常用的,可以参考笔者之前的关于多线程的一些比较实用的文章。
private void buttonTest_Click(object sender, EventArgs e) { BackgroundWorker worker = new BackgroundWorker(); worker.WorkerReportsProgress = true; worker.DoWork += Bw_DoWork; worker.ProgressChanged += Bw_ProgressChanged; worker.RunWorkerAsync(); } private void Bw_ProgressChanged(object sender, ProgressChangedEventArgs e) { labelProcess.Text = e.ProgressPercentage.ToString(); } private void Bw_DoWork(object sender, DoWorkEventArgs e) { var worker = sender as BackgroundWorker; for (int i = 0; i < 100; i++) { worker.ReportProgress(i); Thread.Sleep(100); } }
结果如下图
如对本文有疑问,请提交到交流论坛,广大热心网友会为你解答!! 点击进入论坛