窗体与数据的异步加载--BackgroundWorker
分而治之——窗体与数据的异步加载
C/S模式的客户端通常需要处理大量的数据,当数据量较大而窗体的控件多功能复杂的时候,如果窗体和数据同步加载,将会使程序的性能大大降低,比如说窗体在加载的时候会变成一片空白,等数据全部加载完了窗体的控件才显示出来。这种情况下用户只能等待窗体的完全加载,而不能做任何其他的事情,降低了用户的体验度。采用异步加载的方式的话,可以让与数据无关的部分先加载,而让大量的数据处理以异步的方式进行,即常说的在后台处理。
.net
2.0提供了一种非常简单的机制来实现这样的异步处理,System.Windows.Forms中的类BackgroundWorker是处理这一任务的主要力量,它允许我们在单独的专用线程上运行操作。
MSDN对该类的说明:
- “若要设置后台操作,请为 DoWork 事件添加一个事件处理程序。在此事件处理程序中调用耗时的操作。若要启动该操作,请调用
RunWorkerAsync。若要收到进度更新通知,请对 ProgressChanged 事件进行处理。若要在操作完成时收到通知,请对
RunWorkerCompleted 事件进行处理。” - “必须非常小心,确保在 DoWork 事件处理程序中不操作任何用户界面对象。而应该通过 ProgressChanged 和
RunWorkerCompleted 事件与用户界面进行通信。” - “如果后台操作需要参数,请在调用 RunWorkerAsync 时给出参数。在 DoWork 事件处理程序内部,可以从
DoWorkEventArgs.Argument 属性中提取该参数。”
用一个图来大致描述一下BackgroudWorder的工作情况:
比如要在窗体加载的的同时执行数据读取的工作,大致有以下几个主要的步骤 :
- 创建一个BackgroudWorder的实例:
//System.Windows.Forms,只在.net 2.0中提供
BackgroundWorker backgroudWorker = new
BackgroundWorker(); - 添加DoWork的事件处理程序,该程序负责执行异步的数据加载:
this.backgroudWorker.DoWork += new
DoWorkEventHandler(backgroudWorker_DoWork);//加载数据
void backgroudWorker_DoWork(object sender,
DoWorkEventArgs e){
myDataAdapter.Fill(ds.Tables["tableName"]);
}
- 添加RunWorkerCompleted 事件处理程序,数据加载完成的时候刷新datagrid:
this.backgroudWorker.RunWorkerCompleted += new
RunWorkerCompletedEventHandler(backgroudWorker_RunWorkerCompleted);//刷新datagrid。只有数据全部加载完的时候才让界面的控件去读取数据源的数据,加快了界面的初始化速度
void backgroudWorker_RunWorkerCompleted(object
sender, RunWorkerCompletedEventArgs e){
gridcontrol.RefreshDataSource();
}
- 【可选】添加ProgressChanged,将ReportProgress(arg)中传递过来的arg通知其他线程,比如说报告给进度条(progressBar)。
this.backgroudWorker.ProgressChanged += new
ProgressChangedEventHandler(backgroudWorker_ProgressChanged);//报告处理的进度
void backgroudWorker_ProgressChanged(object sender,
ProgressChangedEventArgs e){
//ProgressPercentage为ReportProgress(arg)中传递过来的argprogressBar1.Value = e.ProgressPercentage;
}
注意:在调用ReportProgress方法,那么请确定你已经设置了BackgroudWorker的WorkerReportsProgress的属性为true,该属性默认为false。
如果有多个异步处理程序需要执行,那么可以创建多个BackgroudWorker对象的实例,比如说我需要一次读取数据集的一部分(worker_A),等这部分执行完了在读取另外的一部分(worker_B),那么我们可以在A结束的时候(RunWorkerCompleted
)启动B,从而形成一种串联的结果,达到多次异步处理的目的。除了串行的工作之外,多个BackgroudWorder的实例也可以并行地执行,即我们可以同时启动多个后台处理的任务,但是需要保证他们之间不会有共享资源的冲突。
浙公网安备 33010602011771号