BackgroundWorker 类
在单独的线程上执行操作。
BackgroundWorker 类允许您在单独的专用线程上运行操作。耗时的操作(如下载和数据库事务)在长时间运行时可能会导致用户界面 (UI) 似乎处于停止响应状态。
如果您需要能进行响应的用户界面,而且面临与这类操作相关的长时间延迟,则可以使用 BackgroundWorker 类方便地解决问题。
若要在后台执行耗时的操作,请创建一个 BackgroundWorker,侦听那些报告操作进度并在操作完成时发出信号的事件。
可以通过编程方式创建 BackgroundWorker,也可以将它从“工具箱”的“组件”选项卡中拖到窗体上。
如果在 Windows 窗体设计器中创建 BackgroundWorker,则它会出现在组件栏中,而且它的属性会显示在“属性”窗口中。
若要设置后台操作,请为 DoWork 事件添加一个事件处理程序。在此事件处理程序中调用耗时的操作。
若要启动该操作,请调用 RunWorkerAsync。若要收到进度更新通知,请对 ProgressChanged 事件进行处理。
若要在操作完成时收到通知,请对 RunWorkerCompleted 事件进行处理。
说明:
您必须非常小心,确保在 DoWork 事件处理程序中不操作任何用户界面对象。
而应该通过 ProgressChanged 和 RunWorkerCompleted 事件与用户界面进行通信。
BackgroundWorker 事件不跨 AppDomain 边界进行封送处理。请不要使用 BackgroundWorker 组件在多个 AppDomain 中执行多线程操作。
如果后台操作需要参数,请在调用 RunWorkerAsync 时给出参数。在 DoWork 事件处理程序内部,可以从 DoWorkEventArgs.Argument 属性中提取该参数。
请注意:在你调用的后台线程里一定要加上Thread.Sleep(100)这一句,
别小看这条语句,他使得后台线程运行时可以释放出足够的时间在前台做操作。
实例如下,首先看界面
程序实现点击Start按钮在后台线程生成制定数量的GUID,写到listbox中,点击End后停止后台线程。
1.首先写好函数,此函数我们要在后台运行处理,同事报告进度,还要返回结果
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | private int GetDate(BackgroundWorker worker, DoWorkEventArgs e) { //获取传入的参数 int maxRecord = ( int )e.Argument; int percent = 0; for ( int i = 0; i < maxRecord; i++) { if (worker.CancellationPending) return i; percent = ( int )(( double )i / ( double )maxRecord * 100); //下边这句执行完后激活ProgressChanged事件 worker.ReportProgress(percent, new KeyValuePair< int , string >(i, Guid.NewGuid().ToString())); //让后台线程Sleep一段时间非常有用,这样前台UI中用户可以做一些其他的输入操作,不至于傻等 Thread.Sleep(100); } return maxRecord; } |
2.设置backgroundWorker1的属性,WorkerReportProgress=true,WorkerSupportsCancellation=true
3.写DoWork,ProgressChanged,RunWorkerCompleted事件
1 2 3 4 5 6 7 8 9 10 11 12 13 | private void backgroundWorker1_DoWork( object sender, DoWorkEventArgs e) { try { BackgroundWorker worker = sender as BackgroundWorker; e.Result = GetDate(worker, e); } catch (Exception ex) { MessageBox.Show(ex.Message); throw ; } } |
1 2 3 4 5 6 7 | private void backgroundWorker1_ProgressChanged( object sender, ProgressChangedEventArgs e) { KeyValuePair< int , string > record = (KeyValuePair< int , string >)e.UserState; this .label1.Text = string .Format( "已经计算了{0}条" , record.Key); this .progressBar1.Value = e.ProgressPercentage; this .listBox1.Items.Add(record.Value); } |
1 2 3 4 5 6 7 8 9 10 11 12 13 | private void backgroundWorker1_RunWorkerCompleted( object sender, RunWorkerCompletedEventArgs e) { try { this .label1.Text = string .Format( "已经完成,总计{0}" , e.Result); this .btn_start.Enabled = true ; btn_end.Enabled = false ; } catch (Exception ex) { MessageBox.Show(ex.Message); } } |
4.点击Start时的代码
1 2 3 4 5 6 7 8 9 | private void btn_start_Click( object sender, EventArgs e) { if ( this .backgroundWorker1.IsBusy) return ; this .listBox1.Items.Clear(); this .backgroundWorker1.RunWorkerAsync(100); this .btn_start.Enabled = false ; this .btn_end.Enabled = true ; } |
点击Start后,this.backgroundWorker1.RunWorkerAsync(100),让Getate生成100个GUID,写入listBox中。
开始执行DoWork中的代码,同时将参数100封装在DoWorkEventArgs中,通过e.Argument获取,类型是object,需要转换程你需要的类型。
5.最后写取消事件
1 2 3 4 | private void btn_end_Click( object sender, EventArgs e) { this .backgroundWorker1.CancelAsync(); } |
OK看下运行结果:
运行时界面可以拖动,不是死锁状态。
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】凌霞软件回馈社区,博客园 & 1Panel & Halo 联合会员上线
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步