当前位置: 首页 > news >正文

BackgroundWorker理解和使用

BackgroundWorker理解和使用

核心概念

1. DoWork —— 后台线程真正干活的地方(自定义事件函数)

运行在 子线程
做耗时操作:计算、读取文件、网络请求、循环
绝对不能直接改控件

2. ReportProgress —— 后台 → UI 发消息、传数据(实例方法)

后台线程调用
作用:把进度、结果、状态 发给 UI
第一个参数:进度百分比
第二个参数:自定义数据(e.UserState)

3. ProgressChanged —— UI 线程接收消息、更新界面(自定义事件函数)

运行在 UI 主线程
可以随便改控件
接收后台传来的:e.ProgressPercentage、e.UserState

4. RunWorkerCompleted —— 任务最终结束,UI 判断结果(自定义事件函数)

运行在 UI 主线程
在这里判断 3 种状态:
e.Cancelled → 是否取消
e.Error → 是否出错
都没有 → 正常完成

5.常用状态

IsBusy

开启任务需要判断是否已经有任务运行,有了就不能RunWorkerAsync(设置条件限定指定数量的跑)
结束后台任务需要判断是否能够结束,即是否有后台任务跑,没有也不能取消CancelAsync

e.Cancel vs e.Cancelled

一个只写不读用于DoWork事件中接受取消信号设置e.Cancel=True,一个只读不写用于RunWorkerCompleted事件中判断任务是否被取消

worker.CancellationPending

根据该条件判断是否被取消(Pending即将到来的意思)

WinForm例子

// 应该是WinForm的
//WinForm当中基类是Form类
//
using System;
using System.ComponentModel;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;namespace MultiThreadDemo
{public partial class Form1 : Form{
//后台工作线程 还有计时器 使用的是Forms.Timer  int用于数据计数private BackgroundWorker bgWorker;private System.Windows.Forms.Timer displayTimer;//private int dataCounter = 0;//初始化组件 初始化BackgroundWorker Timerpublic Form1(){InitializeComponent();InitializeBackgroundWorker();InitializeTimer();}private void InitializeComponent(){this.lblData = new Label();//创建的Labelthis.btnStart = new Button();//Buttonthis.btnStop = new Button();//Button For Stopthis.lstLog = new ListBox(); //listBox展示数据this.lblStatus = new Label();//标签this.SuspendLayout();//???什么布局 // Label显示数据 :设置属性 Font Location设置的坐标点50,30this.lblData.Font = new Font("Microsoft YaHei", 14F);this.lblData.Location = new Point(50, 30);//使用的是绝对定位???this.lblData.Size = new Size(300, 40);//大小像素设置 整个空间可以设置this.lblData.Text = "等待采集...";//文本Textthis.lblData.BackColor = Color.LightYellow;//轻黄色// 开始按钮this.btnStart.Location = new Point(50, 90);this.btnStart.Size = new Size(100, 35);this.btnStart.Text = "开始采集";//绑定的事件 EventHandlerthis.btnStart.Click += new EventHandler(this.btnStart_Click);// 停止按钮this.btnStop.Location = new Point(160, 90);this.btnStop.Size = new Size(100, 35);this.btnStop.Text = "停止采集";this.btnStop.Enabled = false;this.btnStop.Click += new EventHandler(this.btnStop_Click);// 日志列表this.lstLog.Location = new Point(50, 140);this.lstLog.Size = new Size(400, 200);// 状态标签this.lblStatus.Location = new Point(50, 360);this.lblStatus.Size = new Size(400, 25);this.lblStatus.Text = "状态:就绪";// Form设置this.ClientSize = new Size(500, 420);this.Controls.AddRange(new Control[] { this.lblData, this.btnStart, this.btnStop, this.lstLog, this.lblStatus });//AddRange 表示添加的参数是一个数组this.Text = "多线程UI更新演示";this.ResumeLayout(false);//一次性计算所有控件位置}private void InitializeBackgroundWorker(){bgWorker = new BackgroundWorker();//关联实例化对象bgWorker.WorkerReportsProgress = true;//backgroundWorker支持进度bgWorker.WorkerSupportsCancellation = true;//支持取消// 后台执行的工作bgWorker.DoWork += (sender, e) =>{//设置具体的工作逻辑 通过事件机制 //类型转换 as关键字 也是断言?断言这个类型是BackgroundWorker类型var worker = sender as BackgroundWorker;for (int i = 0; i < 100; i++){//CancellationPending判断是否取消//就是用这个来判断是否取消的Pending Pending是即将发生的意思if (worker.CancellationPending){//worker判断是否取消 应该是一个属性方法e.Cancel = true;//为什么给这个赋值??//这个表示是根据这个取消逻辑取消了 //是一个状态值的设定 事件参数值的设定取消了break;}// 模拟数据采集Thread.Sleep(200); // 模拟耗时操作int value = new Random().Next(0, 100);//后台线程报告过程 不是生成报告 而是像UI线程报告 可以修改控件属性//也就是这个阶段就是出了核心计算结果了worker.ReportProgress(0, value);// 在worker线程中不能直接操作UI// 需要用Invoke封送到UI线程this.Invoke(new Action(() =>{AddLog($"后台线程ID:{Thread.CurrentThread.ManagedThreadId} 采集到数据:{value}");}));}};//此处这个事件函数就是定义的如何根据e.UserState 更新组件 //此处已经是UI线程了// 进度报告(能自动在UI线程执行)bgWorker.ProgressChanged += (sender, e) =>{int data = (int)e.UserState;UpdateUIWithData(data);};// 完成事件 回调 判断是否取消 取消不给数据bgWorker.RunWorkerCompleted += (sender, e) =>{    //在此处判断是否已经被取消 但是这里用的是Cancelled 而不是Cancelif (e.Cancelled){AddLog("采集被取消");lblStatus.Text = "状态:已停止";}else{AddLog("采集完成");lblStatus.Text = "状态:完成";}btnStart.Enabled = true;btnStop.Enabled = false;};}private void InitializeTimer(){displayTimer = new System.Windows.Forms.Timer();displayTimer.Interval = 1000;displayTimer.Tick += (sender, e) =>{lblStatus.Text = $"状态:采集中,已采集{dataCounter}条数据";};}// ProgressChanged自动在UI线程执行private void UpdateUIWithData(int data){dataCounter++;//UI线程直接操作组件lblData.Text = $"当前数据:{data}";lblData.BackColor = data > 80 ? Color.LightCoral : Color.LightYellow;}private void AddLog(string message){// 检查是否需要Invokeif (lstLog.InvokeRequired){// 方式1:使用Invoke(同步)lstLog.Invoke(new Action<string>(AddLog), message);}else{lstLog.Items.Insert(0, $"[{DateTime.Now:HH:mm:ss.fff}] {message}");if (lstLog.Items.Count > 20) lstLog.Items.RemoveAt(20);}}private void btnStart_Click(object sender, EventArgs e){if (!bgWorker.IsBusy){dataCounter = 0;lstLog.Items.Clear();AddLog($"UI线程ID:{Thread.CurrentThread.ManagedThreadId}");AddLog("开始采集数据...");bgWorker.RunWorkerAsync();displayTimer.Start();btnStart.Enabled = false;btnStop.Enabled = true;lblStatus.Text = "状态:采集中...";}}private void btnStop_Click(object sender, EventArgs e){if (bgWorker.IsBusy){bgWorker.CancelAsync();displayTimer.Stop();AddLog("正在停止采集...");}}}
}