C# (VS2019 Frameworks) 背景程序组件BackgroundWorker 的基本和使用

news2024/11/27 15:29:56

前言:

C#的应用软件中,经常要考虑到UI的相应和处理的程序(尤其占用时间很长的程序)之前的相应配合问题。

传统的思路,用线程的控制方法,加原子锁等方法,可是,再怎么搞都没有 windows C#自带的 BackgroundWorker 的方法更高效和稳定。

因为,`BackgroundWorker` 组件是实现异步编程的一种方式,它允许开发者在不阻塞主线程的情况下执行耗时操作,并通过事件与主线程安全地交互。
这个是windows内部,基于操作系统的工具。

在下面的参考代码里面,我们做了一个简单的带进度条的后台进程程序。


BackgroundWorker 的基本概念:

在C#中,BackgroundWorker 是一个组件,用于在后台线程中执行长时间运行的任务,而不会影响用户界面的响应性。BackgroundWorker 允许你在后台线程中执行操作,同时可以安全地与主线程(通常是UI线程)通信。

1.2 属性和方法:

 属性:

- `CancellationPending`: 一个只读属性,用于指示是否已经请求取消后台操作。如果用户请求取消操作,此属性将返回 `true`。

- `IsBusy`: 指示 `BackgroundWorker` 是否正在执行操作。

- `WorkerReportsProgress`: 用于标识,你是设置或获取 `BackgroundWorker` 报告进度更改。

- `WorkerSupportsCancellation`: 用于设置或获取 `BackgroundWorker` 是否支持取消操作。

事件:

- `DoWork`: 当 `RunWorkerAsync` 方法被调用时,此事件被触发。通常在此事件的处理程序中执行后台任务。

- `ProgressChanged`: 当 `ReportProgress` 方法被调用时,此事件被触发。可以在事件处理程序中更新用户界面以反映进度。

- `RunWorkerCompleted`: 当后台操作完成时,无论是正常完成、被取消还是发生错误,此事件都会被触发。

方法:(public)

- `CancelAsync`: 请求取消后台操作。如`WorkerSupportsCancellation` 属性设置为 `true`,此方法将触发 `CancellationPending` 属性变为 `true`。

- `ReportProgress`: 报告后台操作的进度。如 `WorkerReportsProgress` 属性设置为 `true`,可以使用此方法来更新进度指示器或执行其他与进度相关的操作。

- `RunWorkerAsync`: 启动后台操作

- `RunWorkerAsync (object argument)`: 带有参数的 `RunWorkerAsync` 方法。

受保护的虚方法:(只能在本背景类里面被调用,且可以重写和拓展)(protected)

- `OnDoWork(DoWorkEventArgs e)`: 当 `DoWork` 事件被触发时,此方法被调用。通常在此方法中实现后台任务的逻辑。

- `OnProgressChanged(ProgressChangedEventArgs e)`: 当 `ProgressChanged` 事件被触发时,此方法被调用。可以在此处更新进度信息。

- `OnRunWorkerCompleted(RunWorkerCompletedEventArgs e)`: 当 `RunWorkerCompleted` 事件被触发时,此方法被调用。可以在此处处理后台操作完成后的清理工作或结果。

 BackgroundWorker 具有的属性和方法如上,大多数是字面意思,我们读的懂,就可以用,我后面列举两个例子:


2 构建 BackgroundWorker 的方法:

2.1 加载


菜单: 视图\工具箱\组件\ 里面,可以找到BackgroundWorker ,然后,直接拖拽到你的主FROM

在主窗口的下沿:会出现定义。

2.2 属性

WorkerReportsProgress(如果需要报告进度)和 WorkerSupportsCancellation(如果需要支持取消操作)


3 使用方法 

3.3 背景Action的定义

3.3.1 DoWork方法

双击会自动进入背景处理程序DoWork方法:在这里写你的背景动作。

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            // 在这里编写长时间运行的任务


        }

 当然,你双击的时候,绑定是自动的

            this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);


3.4 过程进度和进度条的实现:

3.4.1 加入StatusStrip 状态栏:

3.4.2 加入进度条:

 3.4.3 绑定到背景程序:

我们先看一下前面,1.2的属性和方法,和进度相关的有两个,一个是事件一个是报告进度,

- `WorkerReportsProgress`: 用于设置或获取 `BackgroundWorker` 是否报告进度更改。

- `ReportProgress`: 报告后台操作的进度。如 `WorkerReportsProgress` 属性设置为 `true`,可以使用此方法来更新进度指示器或执行其他与进度相关的操作。

- `OnProgressChanged(ProgressChangedEventArgs e)`: 当 `ProgressChanged` 事件被触发时,此方法被调用。可以在此处更新进度信息。 

 在绑定之前,我们先搞清楚,这3个接口的意义,

WorkerReportsProgress,用来表示是否需要报告进度。ReportProgress 方法(被调用的时候,当然,一般是在(背景任务中)DoWork中被调用。由于,WorkerReportsProgress = ture, ReportProgress 调用的时候会触发事件,OnProgressChanged,并把ReportProgress输入的进度的数值0到100,通过事件EvengArgs给到事件处理函数ProgressChanged。


3.5 启动任务

启动 BackgroundWorker的方法, RunWorkerAsync ,有时候可以带参数,object argument,object argument 参数非常有用,因为它允许你将数据传递给后台工作线程。

private void btnStart_Click(object sender, EventArgs e)
{
    // 启动后台工作
    backgroundWorker1.RunWorkerAsync();
}

3.6 完成任务事件

RunWorkerCompleted事件在后台程序完成或者取消的时候,会被触发

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    // 检查后台工作是否成功完成
    if (e.Error != null)
    {
        // 处理错误
        MessageBox.Show("发生错误: " + e.Error.Message);
    }
    else if (e.Cancelled)
    {
        // 处理取消操作
        MessageBox.Show("操作已取消。");
    }
    else
    {
        // 使用 e.Result 获取 DoWork 事件处理器的结果
        MessageBox.Show("操作完成: " + e.Result);
    }
}

3.7 后台的取消:


3.7.1 CancellationPending 属性

指示是否已经请求取消后台操作

3.7.2 WorkerSupportsCancellation 属性

取消后台进程是否使能

3.7.3 请求取消后台方法:CancelAsync

WorkerSupportsCancellation  == true,时候,将触发CancellationPending = true


4 参考代码:

在下面的参考代码里面,我们做了一个简单的带进度条的后台进程程序。

4.0 初始化:

【作者案】BackgroundWorker ,上面的定义的属性、事件、方法和接口,对于public的定义,我们可以之间用"."来调用,而protected的方法,需要进行实例的初始化。而初始化的时候,EventArgs需要传递的是Handler,例如:ProgressChangedEventArgs,对应ProgressChangedEventHandler ,在初始化的时候也可以绑定起来。

在Form的InitializeComponent定义里面,我们可以如下定义:

         // 
            // backgroundWorker1
            // 
            this.backgroundWorker1.WorkerReportsProgress = true;
            this.backgroundWorker1.DoWork += new System.ComponentModel.DoWorkEventHandler(this.backgroundWorker1_DoWork);
            this.backgroundWorker1.ProgressChanged += new System.ComponentModel.ProgressChangedEventHandler(this.backgroundWorker1_ProgressChanged);
            this.backgroundWorker1.RunWorkerCompleted += new System.ComponentModel.RunWorkerCompletedEventHandler(this.backgroundWorker1_RunWorkerCompleted);

4.1 启动后台

4.1.1 不带参数的启动

// 在窗体中,启动 BackgroundWorker 并传递文件路径
private void btnStartProcess_Click(object sender, EventArgs e)
{
    if(!backgroundWorker1.IsBusy){
        backgroundWorker1.RunWorkerAsync();
    }
}

 通过IsBusy先判断,是否已经启动了,避免重复启动。

4.1.2 带参数的启动

// 在窗体中,启动 BackgroundWorker 并传递文件路径
private void btnStartProcess_Click(object sender, EventArgs e)
{
    string filePath = "path/to/your/file.txt";
    backgroundWorker1.RunWorkerAsync(filePath);
}

【案】,注意: RunWorkerAsync的接口

4.2 后台执行任务

 4.2.1 模拟进度更新:

        private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
        {
            // 在这里编写长时间运行的任务
            BackgroundWorker worker = sender as BackgroundWorker;
            for (int i = 0; i <= 100; i++)
            {
                // 模拟工作
                Thread.Sleep(10); // 模拟耗时操作
                                  // 报告进度
                worker.ReportProgress(i); // 这里的 i 将作为 ProgressPercentage
            }

        }

4.2.2 模拟代入一个文件路径参数 

// 在 BackgroundWorker 的 DoWork 事件处理器中使用参数
private void backgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
{
    BackgroundWorker worker = sender as BackgroundWorker;
    string filePath = e.Argument as string; // 从参数中获取文件路径

    if (!worker.CancellationPending)
    {
        // 使用 worker 执行后台任务...
         if (!string.IsNullOrEmpty(filePath) && File.Exists(filePath))
        {
        // 使用文件路径执行后台任务
        // 例如,读取文件内容并进行处理
        string fileContent = File.ReadAllText(filePath);
        // ... 对文件内容进行处理 ...

        e.Result = "处理完成"; // 可以将结果设置在 e.Result 中,稍后在 RunWorkerCompleted 事件中使用
        }
        else
        {
            e.Cancel = true; // 如果文件路径无效或文件不存在,取消操作
            worker.ReportProgress(0, "文件路径无效或文件不存在。");
         }

   }

   
}

 BackgroundWorker worker = sender as BackgroundWorker;

这行代码的目的是将事件的 sender 参数转换为 BackgroundWorker 类型,以便使用 BackgroundWorker 类的成员。如果转换成功,worker 将是一个指向原始 BackgroundWorker 实例的引用

string filePath = e.Argument as string; // 从参数中获取文件路径

4.3 后台完成

private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
{
    if (e.Cancelled)
    {
        MessageBox.Show("操作已取消。");
    }
    else if (e.Error != null)
    {
        MessageBox.Show("发生错误: " + e.Error.Message);
    }
    else
    {
        // 使用 DoWork 事件处理器的结果
        MessageBox.Show("操作结果: " + e.Result);
    }
}

5 运行结果展示:

我在Form的底部加了一个进度条,然后,运行后台模拟进度后,显示如下:

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1961886.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

大数据学习之Flink基础(补充)

Flink基础 1、系统时间与事件时间 系统时间&#xff08;处理时间&#xff09; 在Sparksreaming的任务计算时&#xff0c;使用的是系统时间。 假设所用窗口为滚动窗口&#xff0c;大小为5分钟。那么每五分钟&#xff0c;都会对接收的数据进行提交任务. 但是&#xff0c;这里有…

【HadoopShuffle原理剖析】基础篇二

Shuffle原理剖析 Shuffle&#xff0c;是指对Map输出结果进行分区、排序、合并等处理并交给Reduce的过程。分为Map端的操作和Reduce端的操作。 Shuffle过程 Map端的Shuffle Map的输出结果首先被缓存到内存&#xff0c;当缓存区容量到达80%&#xff08;缓冲区默认100MB&#xff…

[论文笔记]思维链提示的升级版——回退提示

引言 今天又带来一篇提示策略的论文笔记&#xff1a;TAKE A STEP BACK: EVOKING REASONING VIA ABSTRACTION IN LARGE LANGUAGE MODELS。 作者提出了回退提示(STEP-BACK PROMPTING)技术&#xff0c;使大模型能够进行抽象&#xff0c;从包含具体细节的实例中推导出高层次的概念…

centos7 docker空间不足

今天在使用docker安装镜像的时候&#xff0c;出现报错 查看原因&#xff0c;发现是分区空间不足导致的 所以考虑进行扩容 首先在vmware扩容并没有生效 因为只是扩展的虚拟空间&#xff0c;并不支持扩展分区大小&#xff0c;下面对分区进行扩容 参考&#xff1a; 分区扩容 主…

【echarts】echarts-liquidfill 水球图

echarts-liquidfill3兼容echarts5 echarts-liquidfill2兼容echarts4 npm install echarts npm install echarts-liquidfill设置水球图背景色和内边框样式 var option {series: [{type: liquidFill,data: [0.6, 0.5, 0.4, 0.3],backgroundStyle: {borderWidth: 5,//边框宽度bo…

怎样看待AI就业冲击?

技术进步对于就业的影响&#xff0c;从工业革命开始就是社会的焦点和研究的关注点。具有“卢德主义”性质的运动和思潮&#xff0c;曾经以各种面貌反复出现。不过&#xff0c;无论是从原因穷究结果&#xff0c;还是从本质看到表象&#xff0c;AI就业冲击这一次来得真的不同以往…

申请美区 Apple ID 完整步骤图解,轻松免费创建账户

苹果手机在下载一些软件时需要我们登录其 Apple ID 才能下载&#xff0c;但是由于一些限制国内的 Apple ID 在 App Store 中有一些限制不能下载某些软件&#xff0c;如何解决这个问题&#xff1f;那就是申请一个美区 Apple ID&#xff0c;怎么申请国外苹果账户呢&#xff1f;下…

国家超算互联网平台:模型服务体验与本地部署推理实践

目录 前言一、平台显卡选用1、显卡选择2、镜像选择3、实例列表4、登录服务器 二、平台模型服务【Stable Diffusion WebUI】体验1、模型运行2、端口映射配置3、体验测试 三、本地模型【Qwen1.5-7B-Chat】推理体验1、安装依赖2、加载模型3、定义提示消息4、获取model_inputs5、生…

typescript中interface常见3种用法

文章目录 函数类型对象类型【自命名】&#xff1a; (函数)对象类型 函数类型 作用&#xff1a;声明一个函数接口&#xff1a;可用于类型声明 | 不可implements 对象类型 作用&#xff1a;声明对象具备哪些实例接口&#xff1a;可用于类型 | 可implements 【自命名】&…

【C#】ThreadPool的使用

1.Thread的使用 Thread的使用参考&#xff1a;【C#】Thread的使用 2.ThreadPool的使用 .NET Framework 和 .NET Core 提供了 System.Threading.ThreadPool 类来帮助开发者以一种高效的方式管理线程。ThreadPool 是一个线程池&#xff0c;它能够根据需要动态地分配和回收线程…

DATE_ADD、DATE_SUB Function - Mysql

DATE_ADD、DATE_SUB Function - SQL DATE_ADD() 和 DATE_SUB() 用于在日期或日期时间上增加或减少指定的时间间隔。 1. DATE_ADD() DATE_ADD() 函数用于向指定的日期或日期时间值添加一个时间间隔。 DATE_ADD(date, INTERVAL expr unit)date: 要添加时间间隔的日期或日期时间…

【Lampiao靶场渗透】

文章目录 一、IP地址获取 二、信息收集 三、破解SSH密码 四、漏洞利用 五、提权 一、IP地址获取 netdiscover -i eth0 Arp-scan -l Nmap -sP 192.168.78.0/24 靶机地址&#xff1a;192.168.78.177 Kali地址&#xff1a;192.168.78.128 二、信息收集 nmap -sV -p- 192.…

实战:ElasticSearch 索引操作命令(补充)

四.ElasticSearch 操作命令 4.1 集群信息操作命令 4.1.1 查询集群状态 &#xff08;1&#xff09;使用 Postman 客户端直接向 ES 服务器发 GET 请求 http://hlink1:9200/_cat/health?v &#xff08;2&#xff09;使用服务端进行查询 curl -XGET "hlink1:9200/_cat/h…

装饰大师——装饰模式(Python实现)

大家好&#xff0c;今天我们继续来讲结构型设计模式&#xff0c;上一期我们介绍了组合模式&#xff0c;这个模式特别适合用于处理树形结构的问题&#xff0c;它能够让我们像处理单个对象一样来处理对象组合。 装饰模式&#xff08;Decorator Pattern&#xff09;是一种结构型设…

最新彩虹自助下单代发卡码知识付费商城多模板系统完整版去授权源码V6.9

最新彩虹的知识付费商城源码&#xff0c;后台可以选择多套模板&#xff0c;完整版去授权,支持对接多个资源网站&#xff0c;不怕无资源 推荐用宝塔上传后直接访问即可根据提示安装。 后面用户名/密码&#xff1a;admin/123456 PHP推荐使用7.0及以上版本 V6.9 1.修复SQL注入…

k8s 部署RuoYi-Vue-Plus之ingress域名解析

可参看https://blog.csdn.net/weimeibuqieryu/article/details/140798925 搭建ingress 1.创建Ingress对象 ingress-ruoyi.yaml其中host替换为你对应域名&#xff0c;需要解析域名到服务器, 同时为后端服务添加了二级域名解析 api. 访问http://xxx.xyz/就能访问前端&#xff0…

应急靶场(11):【玄机】日志分析-apache日志分析

题目 提交当天访问次数最多的IP&#xff0c;即黑客IP黑客使用的浏览器指纹是什么&#xff0c;提交指纹的md5查看index.php页面被访问的次数&#xff0c;提交次数查看黑客IP访问了多少次&#xff0c;提交次数查看2023年8月03日8时这一个小时内有多少IP访问&#xff0c;提交次数 …

【Redis 初阶】Redis 常见数据类型(Set、Zset、渐进式遍历、数据库管理)

一、Set 集合 集合类型也是保存多个字符串类型的元素的&#xff08;可以使用 json 格式让 string 也能存储结构化数据&#xff09;&#xff0c;但和列表类型不同的是&#xff0c;集合中&#xff1a; 元素之间是无序的。&#xff08;此处的 “无序” 是和 list 的有序相对应的…

重载云台摄像机如何通过国标28181接入到统一视频接入平台(视频国标接入平台)

目录 一、国标GB/T 28181介绍 1、国标GB/T28181 2、内容和特点 二、重载云台摄像机 1、定义 2、结构与设计 3、功能和优势 4、特点 5、应用场景 二、接入准备工作 1、确定网络环境 &#xff08;1&#xff09;公网接入 &#xff08;2&#xff09;专网传输 2、检查重…