享受代码,享受人生

SOA is an integration solution. SOA is message oriented first.
The Key character of SOA is loosely coupled. SOA is enriched
by creating composite apps.
posts - 213, comments - 2315, trackbacks - 162, articles - 45
  博客园  :: 首页  :: 新随笔  :: 联系 :: 订阅 订阅  :: 管理

BackgroudWorker 范例

Posted on 2005-08-18 16:15  idior  阅读(...)  评论(... 编辑 收藏
     在很多场合下, 你需要在主(UI)线程中运行一些比较耗时间的任务,比如以下的任务

l         Image downloads

l         Web service invocations

l         File downloads and uploads (including for peer-to-peer applications)

l         Complex local computations

l         Database transactions

l         Local disk access, given its slow speed relative to memory access

这个时候UI就会陷入一种假死的状态,会给用户带来一种很不好的体验. 如何在这里发挥多线程的优势以改善用户体验? .Net2.0System.ComponentModel.BackgroundWorker为我们提供了一个很方便的解决方法.

vs.net2005 101 sample中提供了一个计算素数的例子, 不过那个例子并没有全面演示BackgroundWorker的能力, 尤其是没有对线程工作过程(ReportProgress)中的能力做比较好的演示.因此我重新做了一个Demo.

            
   
    这个例子很简单
, 就是将左边列表中的内容移至的右边, 用一个进度条来显示移动的进度, 当然既然是BackgroundWorker这个时候主界面可以进行其他操作. 

       本文的源代码提供下载, 其中有详细注释, 所以我在此简要介绍一下需要注意的地方.

       BackgroundWorker主要通过对DoWork  ProgressChanged  RunWorkerCompleted三个事件的处理来完成任务. 需要注意在DoWork中不能直接操作主界面的元素.比如你在MainForm类中启动了一个BackgroundWorker, DoWork的处理方法中不能直接调用任何MainForm中的成员变量. 但是在ProgressChanged RunWorkerCompleted的事件处理中则无此限制, 可以在后台线程中直接调用主线程中的元素, 这是BackgroundWorker中最有亮点的地方. 虽然在DoWork的处理方法中不能调用但是它也提供了参数传递的方法,可以间接调用.示例如下:

   27     //If your background operation requires a parameter,

   28     //call System.ComponentModel.BackgroundWorker.RunWorkerAsync

   29     //with your parameter. Inside the System.ComponentModel.BackgroundWorker.DoWork

   30     //event handler, you can extract the parameter from the

   31     //System.ComponentModel.DoWorkEventArgs.Argument property.

   32     worker.RunWorkerAsync(leftList);

   27      private void worker_DoWork(object sender, DoWorkEventArgs e)

   28         {

   29             MoveList((BackgroundWorker)sender,e);

   30         }

   31 

   32         private void MoveList(BackgroundWorker worker,DoWorkEventArgs e)

   33         {  //get leftList in Main UI Thread from arguments

   34             IList<string> list = e.Argument as IList<string>;

   35             //...

   36         } 

而在ProgressChangedRunWorkerCompleted事件的处理方法中则更加简单.

   27         private void worker_ProgressChanged(object sender, ProgressChangedEventArgs e)

   28         {

   29             //Add string to the right listBox, we use rightList in Main UI Thread directly

   30             rightList.Add(e.UserState as string); 

   31         }

上述原则可以说是BackgroundWorker最需要注意的地方.

另外一个容易被人粗心漏过的地方是有关属性的设置.

如果你要使BackgroundWorker支持进度汇报和取消功能别忘了在初始化的时候为下面两个属性赋值.

// Specify that the background worker provides progress notifications           

          worker.WorkerReportsProgress = true;

          // Specify that the background worker supports cancellation

          worker.WorkerSupportsCancellation = true;

其它部分就让大家自己看代码吧.

BackgroundWorker内部实现是基于delegate的异步调用.
    
                                                       
源代码下载