分享一个在 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方法,报告进度

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

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

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

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

相关文章

【C++】红黑树及其实现

目录 一、红黑树的定义1.为什么提出红黑树?2.红黑树的概念3.红黑树的性质 二、红黑树的实现1.红黑树的结构2.红黑树的插入2.1 uncle为红色2.2 uncle为黑色,且是grandfather的右孩子2.3 uncle为黑色,且是grandfather的左孩子 3.红黑树的验证 4…

虚拟机网络配置(静态网络)

解决问题:VMware中创建centOS虚拟机后使用ifconfig没有ip地址,但我想在主机(Windows)系统下使用shell连接虚拟机从而方便后续交互。 VMware中编辑->虚拟网络编辑器 (注意需要管理员身份不然会无法修改)…

PV操作经典例题

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 一、前言🚀🚀🚀二、正文☀️☀️☀️三、总结🍓🍓🍓 一、前言🚀🚀&am…

万字长文|下一代系统内存数据加速接口SDXI解读

本文内容分为5章节,总计10535字,内容较多,建议先收藏! 1.SDXI技术产生的背景 2.SDXI相比DMA的优势 3.SDXI实现原理与架构 3.1 描述符环原理解读 3.2 上下文管理介绍 3.3 AKey与RKey解读 3.4 错误日志和状态管理 3.5 跨Function访…

ctfshow web入门 sqli-libs web552--web560

web552 宽字节注入 嗯原理我就不讲了,还是有点复杂后面有时间讲讲 总而言之就是用汉字把\的转义作用抵消了然后正常注入即可 ?id-1包 union select 1,2,3--?id-1包union select 1,(select group_concat(table_name) from information_schema.tables where tab…

事过无悔:人生中的释怀之道

在纷繁复杂的人生旅途中,我们常常会面临各种选择。这些选择,如同指引我们前行的路标,有时让我们欣喜,有时让我们遗憾。然而,我渐渐发现,事过无悔,是我们在面对这些选择时最顶级的释怀之道。 首…

MySQL 常见存储引擎详解(一)

本篇主要介绍MySQL中常见的存储引擎。 目录 一、InnoDB引擎 简介 特性 最佳实践 创建InnoDB 存储文件 二、MyISAM存储引擎 简介 特性 创建MyISAM表 存储文件 存储格式 静态格式 动态格式 压缩格式 三、MEMORY存储引擎 简介 特点 创建MEMORY表 存储文件 内…

节点级、系统级、实车级的LIN测试主要差异点

文章目录 前言一、节点级1.前期准备2.测试执行 二、系统级1.前期准备2.测试执行 三、实车级1.前期准备2.测试执行 总结 前言 LIN协议一致性测试主要指的是物理层(电阻、电容、电压、地偏移、显隐性电平、频率占空比、位时间等)、数据链路层(…

window用户层文件系统fuse(wdm驱动)

dokany https://github.com/dokan-dev/dokany.git 需要安装wdk,2022可以直接通过windows driver扩展安装 项目使用nuget添加wdk依赖 Version of Uwp Package 10.0.26100.0 does not match TargetPlatformVersion 10.0.22621.0. windows sdk版本填写正确的版本号…

算法实验2.2、2.3

2.2主要内容 比较快速排序&#xff0c;归并排序以及堆排序算法的时间效率。了解影响算法执行时间的 主要因素以及如何降低算法的执行时间。 #include<iostream> using namespace std; #include<stdio.h> #include<malloc.h> #include<stdlib.h> #inc…

【论文阅读】-- 研究时间序列可视化,提升用户体验

Investigating Time Series Visualisations to Improve the User Experience 摘要1 引言2 相关工作互动技巧视觉编码坐标系 3 用户研究时间序列可视化互动技巧任务实验设计 4 结果交互技术的效果视觉编码的影响坐标系的影响 5 讨论交互技术的效果视觉编码的影响坐标系的影响 6 …

芒果YOLOv10改进122:注意力机制系列:最新结合即插即用CA(Coordinate attention) 注意力机制,CVPR 顶会助力分类检测涨点!

论文所提的Coordinate注意力很简单,可以灵活地插入到经典的移动网络中,而且几乎没有计算开销。大量实验表明,Coordinate注意力不仅有益于ImageNet分类,而且更有趣的是,它在下游任务(如目标检测和语义分割)中表现也很好。本文结合目标检测任务应用 应专栏读者的要求,写一…

cube-studio开源一站式机器学习平台,在线ide,jupyter,vscode,matlab,rstudio,ssh远程连接,tensorboard

全栈工程师开发手册 &#xff08;作者&#xff1a;栾鹏&#xff09; 一站式云原生机器学习平台 前言 开源地址&#xff1a;https://github.com/tencentmusic/cube-studio cube studio 腾讯开源的国内最热门的一站式机器学习mlops/大模型训练平台&#xff0c;支持多租户&…

【Linux】:环境变量

朋友们、伙计们&#xff0c;我们又见面了&#xff0c;本期来给大家解读一下有关Linux环境变量的相关知识点&#xff0c;如果看完之后对你有一定的启发&#xff0c;那么请留下你的三连&#xff0c;祝大家心想事成&#xff01; C 语 言 专 栏&#xff1a;C语言&#xff1a;从入门…

mac|浏览器链接不上服务器但可以登微信

千万千万千万不要没有关梯子直接关机&#xff0c;不然就会这样子呜呜呜 设置-网络&#xff0c;点击三个点--选择--位置--编辑位置&#xff08;默认是自动&#xff09; 新增一个&#xff0c;然后选中点击完成 这样就可以正常上网了

【嵌入式DIY实例】- LCD ST7735显示DHT11传感器数据

LCD ST7735显示DHT11传感器数据 文章目录 LCD ST7735显示DHT11传感器数据1、硬件准备与接线2、代码实现本文介绍如何将 ESP8266 NodeMCU 板 (ESP-12E) 与 DHT11 (RHT01) 数字湿度和温度传感器连接。 NodeMCU 从 DHT11 传感器读取温度(以 C 为单位)和湿度(以 rH% 为单位)值,…

计算机网络-第5章运输层

5.1运输层协议概述 5.1.1进程之间的通信 运输层向它上面的应用层提供通信服务&#xff0c;它属于面向通信部分的最高层&#xff0c;同时也是用户功能中的最低层。 通信的两端应当是两个主机中的应用进程。 运输层复用和分用&#xff1a;复用指在发送方不同的应用进程都可以…

【机器学习】FFmpeg+Whisper:二阶段法视频理解(video-to-text)大模型实战

目录 一、引言 二、FFmpeg工具介绍 2.1 什么是FFmpeg 2.2 FFmpeg核心原理 2.3 FFmpeg使用示例 三、FFmpegWhisper二阶段法视频理解实战 3.1 FFmpeg安装 3.2 Whisper模型下载 3.3 FFmpeg抽取视频的音频 3.3.1 方案一&#xff1a;命令行方式使用ffmpeg 3.3.2 方案二&a…

基于协同过滤的电影推荐与大数据分析的可视化系统

基于协同过滤的电影推荐与大数据分析的可视化系统 在大数据时代&#xff0c;数据分析和可视化是从大量数据中提取有价值信息的关键步骤。本文将介绍如何使用Python进行数据爬取&#xff0c;Hive进行数据分析&#xff0c;ECharts进行数据可视化&#xff0c;以及基于协同过滤算法…

SuperMap GIS基础产品FAQ集锦(20240701)

一、SuperMap iDesktopX 问题1&#xff1a;对于数据提供方提供的osgb格式的数据&#xff0c;如何只让他生成一个s3mb文件呢&#xff1f;我用倾斜入库的方式会生成好多个s3mb缓存文件 11.1.1 【解决办法】不能控制入库后只生成一个s3mb文件&#xff1b;可以在倾斜入库的时候设…