分享一个在 WinForm 桌面程序中使用进度条展示报表处理进度的例子,提升用户体验

image

前言

在有些比较消耗时间的业务场景中,比如生成报表等,如果没有在操作的过程中向用户反馈操作进度,会让用户以为程序 “死” 掉了,用户体验非常不好。

WinForm 桌面程序项目与 Console 项目不一样,如果 Console 项目,我们可以在处理业务的关键节点时,在控制台打印一些消息向用户报告进度,但是 WinForm 桌面程序项目出于线程安全的原因,是无法在处理业务的过程中同时显示 UI 控件的消息的,即你在处理业务的的关键节点时,向 UI 控件如 TextBox 写一些消息,但实际上 UI 是不会马上同时显示你写的消息的,只有在整个业务处理完后,UI 才会呈现你写的消息,但这时已经太迟了,没有太多意义。所以在 WinForm 桌面程序项目里,要在操作的过程中向用户反馈操作进度,只能通过多线程来处理,一个线程在后台处理业务,一个线程通过委托同步展示业务处理进度,不过手动写多线程代码比较麻烦,所以微软在 .NET 2.0 增加了 BackgroundWorker 类,专门用于处理这种情况。使用 BackgroundWorker 可以轻松地启动一个单独的线程上执行一些操作并进行管理,无需我们操心。

可以将它从 “工具箱” 的 “组件” 选项卡中拖到窗体上,也可以通过编程方式创建 BackgroundWorker 类,本文通过一个实际的详细例子演示如何通过编程方式使用 BackgroundWorker 类,大家可以照着做。

Step By Step 步骤

  1. 创建一个 WinForm 类型的项目

  2. 设计窗体 UI 内容,如图:

    [图片]

  3. 打开窗体如 FrmZqReportHandler 的代码

  4. 在顶部(构造方法之前)添加声明 BackgroundWorker 对象的代码

    // 声明 BackgroundWorker 对象
    private BackgroundWorker m_BackgroundWorker;
    
  5. 在构造方法中实例化及配置 BackgroundWorker 对象,(留意注释

    public FrmZqReportHandler()
    {
    	InitializeComponent();
    
    	m_BackgroundWorker = new BackgroundWorker();            // 实例化 BackgroundWorker 对象
    	m_BackgroundWorker.WorkerReportsProgress = true;        // 设置可以通告进度
    	m_BackgroundWorker.WorkerSupportsCancellation = false;  // 设置不可以取消
    
    	// 声明 DoWork 事件
    	m_BackgroundWorker.DoWork += new DoWorkEventHandler(DoWork);
    
    	// 声明 ProgressChanged 事件
    	m_BackgroundWorker.ProgressChanged += new ProgressChangedEventHandler(UpdateProgress);
    
    	// 声明 RunWorkerCompleted 事件
    	m_BackgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(CompletedWork);
    }
    
  6. 在按钮的单击事件里启动 BackgroundWorker,(留意注释

    private void btnSelectFile_Click(object sender, EventArgs e)
    {
    	// 1. 选择文件
    	// 代码忽略 ......
    
    	// 2. 如果后台线程空闲,则启动后台操作
    	if (!m_BackgroundWorker.IsBusy) {
    		// 启动后台操作,触发 DoWork 事件
    		// 参数可传可不传,暂时没什么有什么作用
    		m_BackgroundWorker.RunWorkerAsync(this);
    	}
    }
    
  7. 编写 DoWork 事件,DoWork 事件中的代码就是后台线程要执行的业务处理方法,(留意注释

    void DoWork(object sender, DoWorkEventArgs e)
    {
    	BackgroundWorker bw = sender as BackgroundWorker;
    
    	// 1. 处理业务逻辑 01
    	// 处理业务逻辑代码 ......
    	// 传递进度,第一个参数是进度值,第二个参数是附加对象,此方法会触发 ProgressChanged 事件
    	bw.ReportProgress(10, obj);
    
    	// ...... 处理业务逻辑代码
    
    	// 7. 处理业务逻辑 07,业务处理完成
    	// 处理业务逻辑代码 ......
    	// 传递进度,将进度值设置为进度条控件的最大值
    	bw.ReportProgress(100, fileUrl);
    }
    
  8. 编写 ProgressChanged 事件,注意:在这个事件里跟 UI 控件交互,(留意注释

    void UpdateProgress(object sender, ProgressChangedEventArgs e)
    {
    	int progress = e.ProgressPercentage;
    	// 根据 `DoWork` 事件传递过来的进度值不断更新进度条的值
    	pgBar.Value = progress;
    
    	// 根据进度值向填写业务处理细节,提高用户体验
    	if (progress == 1)
    	{
    		txtPg.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} ......\r\n");
    	}
    	else if (progress == 10)
    	{
    		txtPg.AppendText(......
    	}
    	// ......
    	else if (progress == 100)
    	{
    		txtPg.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 数据处理后是 [{e.UserState}]\r\n");
    	}
    }
    
  9. 编写 RunWorkerCompleted 事件,此事件在后台操作已完成、被取消或引发异常时发生

    void CompletedWork(object sender, RunWorkerCompletedEventArgs e)
    {
    	if (e.Error != null)
    	{
    		txtPg.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 处理过程中出现错误:[{e.Error}]\r\n");
    	}
    	else
    	{
    		txtPg.AppendText($"{DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff")} 处理完毕");
    	}
    }
    
  10. 至此,代码就完成了,运行效果如下:

    [图片]

总结

  1. BackgroundWorker 类虽然是旧技术,但它在处理 WinForm 业务处理进度,提高用户体验上却是非常好用的,比直接用多线程方便很多,这可见,技术不分新旧,用在恰当的地方最重要。
  2. BackgroundWorker 类几个常用属性
    1. WorkerReportsProgress: 设置能否报告进度,通常设置为 true
    2. WorkerSupportsCancellation: 设置能否中途取消,按需设置
    3. IsBusy: 判断后台线程是否正在工作中,只读属性
    4. CancellationPending: 指示应用程序是否已请求取消后台操作,只读属性
  3. BackgroundWorker 类几个常用方法
    1. RunWorkerAsync: 启动后台操作,此方法会触发 DoWork 事件
    2. CancelAsync: 请求取消挂起的后台操作,此方法只是将 CancellationPending 属性设置为 true,需要在 DoWork 事件中检查 CancellationPending 属性,来决定是否要继续取消后台操作
    3. ReportProgress: 报告进度,此方法会触发 ProgressChanged 事件
  4. BackgroundWorker 类几个常用事件
    1. DoWork: 后台线程,一般在这里处理业务逻辑,不能操作 UI 控件
    2. ProgressChanged: 报告业务处理进度,可以操作 UI 控件
    3. RunWorkerCompleted: 后台操作已完成、被取消或引发异常时触发,可以操作 UI 控件
  5. BackgroundWorker 类使用步骤:
    1. 新建 BackgroundWorder 对象
    2. 根据需求, 设置是否能取消、是否报告进度等
    3. 根据需求,设置好相关事件,DoWorker、ProgressChanged、RunWorkerCompleted
    4. 调用 RunWorkerAsyns() 方法,启动线程;
    5. DoWork 在需要取消的位置,判断 CancellationPending 的值,并做相关处理;
    6. DoWork 在适当的位置调用 ReportProgress方法,报告进度

我是老杨,一个奋斗在一线的资深研发老鸟,让我们一起聊聊技术,聊聊人生。

都看到这了,求个点赞、关注、在看三连呗,感谢支持。

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

C++ initializer_list类型推导

目录 initializer_list C自动类型推断 auto typeid decltype initializer_list<T> C支持统一初始化{ }&#xff0c;出现了一个新的类型initializer_list<T>&#xff0c;一切类型都可以用列表初始化。提供了一种更加灵活、安全和明确的方式来初始化对象。 class…

MIT6.s081 2021 Lab Page tables

Speed up system calls 思路 题目要求在每个进程初始化时为它的页表插入一个页表项&#xff0c;内核通过这样预先缓存页表项的操作&#xff0c;来加速特定系统调用的执行速度。 由于前不久刚过完一遍《OSTEP》&#xff0c;因此我认为自己对页表机制还算比较熟悉&#xff0c;…

Open AI Stream Completion Set Variable Inside Function PHP With Openai-php SDK

题意&#xff1a;使用 OpenAI 的 PHP SDK&#xff08;例如 openai-php&#xff09;来在函数内部设置和完成一个流&#xff08;stream&#xff09;相关的变量 问题背景&#xff1a; How to set variable inside this openai-php sdk function in stream completion ? I am usi…

【笔记】手工部署之linux中开放已安装的mysql与tomcat端口

在需要打包的springboot项目中输入mvn clean package 在target下面获得jar包 进入linux中你想要该jar包存在的位置 将jar包上传至linux中 此时在浏览器中输入linux的ip地址&#xff1a;端口号/mapping路径为404 故&#xff1a; 在linux中另开一个标签页 检查mysql和tomcat已…

JavaFX布局-BorderPane

JavaFX布局-BorderPane 实现方式Java实现FXML实现 综合案例 将容器空间分成五个区域&#xff1a;顶部&#xff08;Top&#xff09;、底部&#xff08;Bottom&#xff09;、左侧&#xff08;Left&#xff09;、右侧&#xff08;Right&#xff09;和中心&#xff08;Center&#…

Java案例找素数(三种方法)

目录 一&#xff1a;问题&#xff1a; 二&#xff1a;思路分析&#xff1a; 三&#xff1a;具体代码&#xff1a; 四&#xff1a;运行结果&#xff1a; 一&#xff1a;问题&#xff1a; 二&#xff1a;思路分析&#xff1a; 三&#xff1a;具体代码&#xff1a; Ⅰ&#xf…

03 _ 类型基础(2):动态类型与静态类型

静态类型语言与动态类型语言 通俗定义 静态类型语言&#xff1a;在编译 阶段确定所有变量的类型 动态类型语言&#xff1a;在执行阶段确定所有变量的类型 Javascript 与 C 对比 静态类型与动态类型对比 其他定义 强类型语言&#xff1a;不允许程序在发生错误后继续执行 语…

【STM32】温湿度采集与OLED显示

一、任务要求 1. 学习I2C总线通信协议&#xff0c;使用STM32F103完成基于I2C协议的AHT20温湿度传感器的数据采集&#xff0c;并将采集的温度-湿度值通过串口输出。 任务要求&#xff1a; 1&#xff09;解释什么是“软件I2C”和“硬件I2C”&#xff1f;&#xff08;阅读野火配…

视频号视频怎么下载保存到手机,视频号视频如何下载到电脑本地

在数字化浪潮的推动下&#xff0c;视频号成为了我们获取信息、分享生活的重要平台。但有时候&#xff0c;我们遇到一些精彩的内容&#xff0c;想要保存下来以便日后观看&#xff0c;却发现视频号并不提供直接的下载功能。下面我就来为大家详细介绍视频号视频下载的方法&#xf…

Datax快速使用之牛刀小试

前言 一次我发现业务他们在用 datax数据同步工具&#xff0c;我尤记得曾经 19 年使用过&#xff0c;并且基于当时的版本还修复了个 BUG并且做了数据同步管道的集成开发。没想到时间过的飞快&#xff0c;业务方基于海豚调度 2.0.6 的版本中有在使用&#xff0c;由于业务方还没有…

大促前夕即高点,综合电商平台的“稀缺”魔法正在消失?

新一期618大促早已结束良久了&#xff0c;但似乎其产生的余韵却仍旧未消散。 从最直观的资本市场走势来看&#xff0c;自这一波618大促陆续开展之后&#xff0c;包括京东、阿里巴巴、拼多多等港美股股价就一改此前的上行态势&#xff0c;持续下滑至今。 事实上&#xff0c;早…

【计算机网络期末复习】例题汇总(一)

重点例题选择填空简答题与传输媒体的接口的特性重点 计算机网络的性能指标计算机网络体系结构例题 选择

【Linux】线程id与互斥(线程三)

上一期我们进行了线程控制的了解与相关操作&#xff0c;但是仍旧有一些问题没有解决 本章第一阶段就是解决tid的问题&#xff0c;第二阶段是进行模拟一个简易线程库&#xff08;为了加深对于C库封装linux原生线程的理解&#xff09;&#xff0c;第三阶段就是互斥。 目录 线程id…

【解锁未来:深入了解机器学习的核心技术与实际应用】

解锁未来&#xff1a;深入了解机器学习的核心技术与实际应用 &#x1f48e;1.引言&#x1f48e;1.1 什么是机器学习&#xff1f; &#x1f48e;2 机器学习的分类&#x1f48e;3 常用的机器学习算法&#x1f48e;3.1 线性回归&#xff08;Linear Regression&#xff09;&#x1…

【PYG】Planetoid中边存储的格式,为什么打印前十条边用edge_index[:, :10]

edge_index 是 PyTorch Geometric 中常用的表示图边的张量。它通常是一个形状为 [2, num_edges] 的二维张量&#xff0c;其中 num_edges 表示图中边的数量。每一列表示一条边&#xff0c;包含两个节点的索引。 实际上这是COO存储格式&#xff0c;官方文档里也有写&#xff0c;…

爬虫逆向实战(41)-某巢登陆(AES、MD5、RSA、滑块验证码)

一、数据接口分析 主页地址&#xff1a;某巢 1、抓包 通过抓包可以发现在登录时&#xff0c;网站首先请求captcha/querySlideImage/来获取滑块验证码的图片&#xff0c;然后请求captcha/checkCode/接口来验证滑块验证码。滑块验证码校验成功后&#xff0c;请求noshiro/getPu…

高性能LDO电路设计,有配套文档

内容&#xff1a; 1、电路文件&#xff08;有仿真状态&#xff09;和PDK&#xff08;TSMC180&#xff09; 2、配套仿真结果文档讲解6页 3、参考资料三篇 指标&#xff1a; LDO 温度系数1.09ppm LDO 环路增益在 64.3dB&#xff0c;相位裕度在 66&#xff0c;系统稳定。 LDO 最大…

抛弃 Neofetch?众多优秀替代方案等你体验!

目录 抛弃 Neofetch&#xff1f;众多优秀替代方案等你体验Neofetch 的替代品FastfetchscreenFetchmacchina 抛弃 Neofetch&#xff1f;众多优秀替代方案等你体验 NeoFetch 是用 Bash 3.2 编写的命令行系统信息工具&#xff0c;该项目的主要开发人员已将 GitHub 存储库存档&…

【漏洞复现】和丰多媒体信息发布系统 QH.aspx 任意文件上传漏洞

0x01 产品简介 和丰多媒体信息发布系统也称数字标牌&#xff08;Digital Signage&#xff09;&#xff0c;是指通过大屏幕终端显示设备&#xff0c;发布商业、财经和娱乐信息的多媒体专业视听系统&#xff0c;常被称为除纸张媒体、电台、电视、互联网之外的“第五媒体”。该系…