窗体与数据的异步加载--BackgroundWorker

分而治之——窗体与数据的异步加载


C/S模式的客户端通常需要处理大量的数据,当数据量较大而窗体的控件多功能复杂的时候,如果窗体和数据同步加载,将会使程序的性能大大降低,比如说窗体在加载的时候会变成一片空白,等数据全部加载完了窗体的控件才显示出来。这种情况下用户只能等待窗体的完全加载,而不能做任何其他的事情,降低了用户的体验度。采用异步加载的方式的话,可以让与数据无关的部分先加载,而让大量的数据处理以异步的方式进行,即常说的在后台处理。


.net
2.0提供了一种非常简单的机制来实现这样的异步处理,System.Windows.Forms中的类BackgroundWorker是处理这一任务的主要力量,它允许我们在单独的专用线程上运行操作。


MSDN对该类的说明:



  1. “若要设置后台操作,请为 DoWork 事件添加一个事件处理程序。在此事件处理程序中调用耗时的操作。若要启动该操作,请调用
    RunWorkerAsync。若要收到进度更新通知,请对 ProgressChanged 事件进行处理。若要在操作完成时收到通知,请对
    RunWorkerCompleted 事件进行处理。”

  2. “必须非常小心,确保在 DoWork 事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和
    RunWorkerCompleted 事件与用户界面进行通信。”

  3. “如果后台操作需要参数,请在调用 RunWorkerAsync 时给出参数。在 DoWork 事件处理程序内部,可以从
    DoWorkEventArgs.Argument 属性中提取该参数。”

 


用一个图来大致描述一下BackgroudWorder的工作情况:窗体与数据的异步加载--BackgroundWorker - liuman823 - liuman823的博客


比如要在窗体加载的的同时执行数据读取的工作,大致有以下几个主要的步骤 :



  1. 创建一个BackgroudWorder的实例:

     


    //System.Windows.Forms,只在.net 2.0中提供


    BackgroundWorker backgroudWorker = new
    BackgroundWorker();


  2. 添加DoWork的事件处理程序,该程序负责执行异步的数据加载:

     


    this.backgroudWorker.DoWork += new
    DoWorkEventHandler(backgroudWorker_DoWork);


    //加载数据


    void backgroudWorker_DoWork(object sender,
    DoWorkEventArgs e)


    {


            myDataAdapter.Fill(ds.Tables["tableName"]);


    }


  3. 添加RunWorkerCompleted 事件处理程序,数据加载完成的时候刷新datagrid:

     


    this.backgroudWorker.RunWorkerCompleted += new
    RunWorkerCompletedEventHandler(backgroudWorker_RunWorkerCompleted);


    //刷新datagrid。只有数据全部加载完的时候才让界面的控件去读取数据源的数据,加快了界面的初始化速度


    void backgroudWorker_RunWorkerCompleted(object
    sender, RunWorkerCompletedEventArgs e)


    {


            gridcontrol.RefreshDataSource();


    }


  4. 【可选】添加ProgressChanged,将ReportProgress(arg)中传递过来的arg通知其他线程,比如说报告给进度条(progressBar)。

     


    this.backgroudWorker.ProgressChanged += new
    ProgressChangedEventHandler(backgroudWorker_ProgressChanged);


    //报告处理的进度


    void backgroudWorker_ProgressChanged(object sender,
    ProgressChangedEventArgs e)


    {


        
    //ProgressPercentage为ReportProgress(arg)中传递过来的arg


         progressBar1.Value = e.ProgressPercentage;


    }


    注意:在调用ReportProgress方法,那么请确定你已经设置了BackgroudWorker的WorkerReportsProgress的属性为true,该属性默认为false。


 


如果有多个异步处理程序需要执行,那么可以创建多个BackgroudWorker对象的实例,比如说我需要一次读取数据集的一部分(worker_A),等这部分执行完了在读取另外的一部分(worker_B),那么我们可以在A结束的时候(RunWorkerCompleted
)启动B,从而形成一种串联的结果,达到多次异步处理的目的。除了串行的工作之外,多个BackgroudWorder的实例也可以并行地执行,即我们可以同时启动多个后台处理的任务,但是需要保证他们之间不会有共享资源的冲突。

posted @ 2011-08-02 22:11  therockthe  阅读(798)  评论(0)    收藏  举报