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

C# backgroundworker类

概念

在C#程序中,经常会有一些耗时较长的CPU密集型运算,如果直接在 UI 线程执行这样的运算就会出现UI不响应的问题。解决这类问题的主要途径是使用多线程,启动一个后台线程,把运算操作放在这个后台线程中完成。但是原生接口的线程操作有一些难度,如果要更进一步的去完成线程间的通信就会难上加难。

C#的BackgroundWorker类是一个用于简化在桌面应用程序(如Windows Forms或WPF)中执行后台任务的工具。它的主要目的是在不阻塞用户界面(UI)的情况下运行耗时操作,同时支持进度报告和任务取消。

主要作用

后台执行耗时任务
在单独的线程中运行长时间操作(如文件下载、数据处理),防止UI线程被阻塞,保持界面响应。

进度更新
允许在后台任务中报告进度(如更新进度条),并自动将更新操作同步到UI线程。

取消支持
提供机制让用户请求取消正在执行的后台任务。

完成通知
在任务完成(成功、取消或出错)后,触发事件以更新UI或处理结果。


关键成员

成员类型说明
DoWork事件后台任务逻辑:在此事件处理程序中编写耗时操作代码。此代码在后台线程执行。
ProgressChanged事件进度更新:通过ReportProgress()方法触发,用于在UI上更新进度(如进度条)。
RunWorkerCompleted事件任务完成通知:在任务结束时触发,处理结果或错误。
RunWorkerAsync()方法启动后台任务
CancelAsync()方法请求取消任务(需设置WorkerSupportsCancellation = true)。
WorkerReportsProgress属性设置为true以启用进度报告功能。
WorkerSupportsCancellation属性设置为true以允许任务取消。


典型使用场景

// 创建BackgroundWorker实例
var worker = new BackgroundWorker 
{ 
    WorkerReportsProgress = true,
    WorkerSupportsCancellation = true 
};

// 订阅事件
worker.DoWork += (sender, e) => 
{
    for (int i = 0; i <= 100; i++) 
    {
        if (worker.CancellationPending) 
        {
            e.Cancel = true;
            return;
        }
        // 模拟耗时操作并报告进度
        worker.ReportProgress(i);
        Thread.Sleep(50);
    }
};

worker.ProgressChanged += (sender, e) => 
{
    // 更新UI进度条(自动在UI线程执行)
    progressBar.Value = e.ProgressPercentage;
};

worker.RunWorkerCompleted += (sender, e) => 
{
    if (e.Cancelled) MessageBox.Show("任务已取消!");
    else if (e.Error != null) MessageBox.Show($"错误:{e.Error.Message}");
    else MessageBox.Show("任务完成!");
};

// 启动任务
worker.RunWorkerAsync();


 

注意事项

  1. 跨线程访问UI

    • DoWork事件在后台线程运行,禁止直接操作UI控件

    • ProgressChangedRunWorkerCompleted事件会自动在UI线程触发,可直接更新UI。

  2. 替代方案
    现代C#更推荐使用async/await配合Task.Run处理异步操作,代码更简洁。但BackgroundWorker仍适用于旧项目或需要深度集成进度/取消逻辑的场景。


与async/await对比

特性BackgroundWorkerasync/await + Task.Run
复杂度基于事件,代码分散线性结构,代码更清晰
取消支持内置CancellationPending机制通过CancellationToken实现
进度报告内置ReportProgress需自定义(如IProgress<T>接口)
适用场景简单后台任务复杂异步操作,需更高灵活性

总结:BackgroundWorker是简化桌面应用后台任务处理的经典工具,适合需要快速实现进度更新和取消功能的场景。但在新项目中,可优先考虑async/await以获得更现代的编程体验。


实例(源码)

public partial class Form2 : Form
{
    public  BackgroundWorker worker = new BackgroundWorker();

    public Form2()
    {
        InitializeComponent();
    }

    private void Form2_Load(object sender, EventArgs e)
    {
        // Worker 工人
        // Reports 报告
        // Progress 进度
        // WorkeyRepoetsProgress 是否支持BackgroundWorker报告异步任务进度的功能。
        worker.WorkerReportsProgress = true;

        // WorkerSupportsCancellation  是否支持异步取消操作
        worker.WorkerSupportsCancellation = true;

        // 三个事件
        // 1 DoWork: 做异步耗时的操作(调用RunWorkerAsync方法之后触发)
        worker.DoWork += Worker_DoWork;

        // 2 ProgressChange 进度发生变化的事件,WorkerReportsProgress属性true的时候触发
        worker.ProgressChanged += Worker_ProgressChanged;

        // 3 RWorkerCompleted 后台操作完成的时候触发,取消或者异常的时候都会触发
        worker.RunWorkerCompleted += Worker_RunWorkerCompleted;

    }

    //做异步任务的函数

    private void Worker_DoWork(object sender, DoWorkEventArgs e)
    {
        //模拟处理超时的操作
        Random rnd = new Random();
        for (int i = 0; i < 80; i++)
        {
            if (worker.CancellationPending) //判断用户是否取消了后台任务
            {
                e.Cancel = true; //取消后台任务
                return;
            }
            else
            {
                //耗时任务(文件读写,通讯、加载tb块)
                Thread.Sleep(rnd.Next(100, 1000)); //休眠100-1000ms之间,模拟耗时的

                //报告进度
                int progress = (int)Math.Round(((i + 1) / 80.0) * 100);
                progress = progress > 100 ? 100 : progress;

                worker.ReportProgress(progress);// 触发进度变化的事件

            }
        }

    }
    //加载进度的函数
    private void Worker_ProgressChanged(object sender, ProgressChangedEventArgs e)
    {
        progressBar1.Value = e.ProgressPercentage;// 把ReportProgress(progress)函数里面的参数传递过来,取出
    }

    //后台操作处理完的函数
    private void Worker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    {
        this.BackColor = Color.Red;// 后台任务执行完之后的操作
    }

    //开始异步任务的按钮
    private void button1_Click(object sender, EventArgs e)
    {
        Console.WriteLine(worker.IsBusy);// backWrork是否是繁忙状态
        if (!worker.IsBusy) // 空闲状态下
        {
            worker.RunWorkerAsync();// 开始后台任务
        }
    }

    //取消异步任务的按钮
    private void button2_Click(object sender, EventArgs e)
    {
        if (worker.IsBusy) //非空闲状态下取消
        {
            worker.CancelAsync();//取消后台任务
        }
    }
}

相关文章:

  • [20250304] 关于 RISC-V芯片 的介绍
  • 游戏引擎学习第149天
  • 快速谱峭度算法解析
  • Ubuntu用户安装cpolar内网穿透
  • leetcode日记(88)对称二叉树
  • MySQL数据库操作
  • 应急响应--流量分析
  • HTML页面中divborder-bottom不占用整个底边,只占用部分宽度
  • Yashan DB 存储结构
  • 19. 大数据-技术生态简介
  • 前端非技术性场景面试题
  • 第4节: 静态路由与动态路由协议(RIP、OSPF)详解
  • 【javaEE】多线程(进阶)
  • Linux 离线部署Ollama和DeepSeek-r1模型
  • 做一做native层面消息实战Looper,Handler,Message
  • 第一章:欢迎来到 HTML 星球!
  • 嵌入式裸机设计--MCU常用裸机架构有哪些?
  • MySQL的安装及配置
  • abbd:`Nx`、`Lerna` 和 `Turborepo`
  • 内网anaconda如何使用代理,避免网络连接失败?
  • 六省会共建交通枢纽集群,中部六省离经济“第五极”有多远?
  • 马上评|训斥打骂女儿致死,无暴力应是“管教”底线
  • 王伟妻子人民日报撰文:81192,一架永不停航的战机
  • 政企共同发力:多地密集部署外贸企业抢抓90天政策窗口期
  • 向猫学习禅修之后,你会发现将生活降格为劳作是多么愚蠢
  • 泽连斯基启程前往土耳其