C#开发WinForm进度条开发

刺骨的言语ヽ痛彻心扉 2022-04-12 03:19 524阅读 0赞

C#开发WinForm进度条开发

文章目录

    • C#开发WinForm进度条开发
  • 前言
  • 实现
  • 结果
    • 补充
  • BackgroundWorker方式

前言

开发windows窗体组件,由于业务复杂需要进度条,使用ProgressBar控件。
winForm弹出窗口有两种方式:非模态窗口方式和模态窗口方式。
Show():非模态窗口方式(可以跟其他界面自由切换,而且不阻塞代码)
ShowDialog():模态窗口(必须关闭了该窗口,后面的代码才会执行,并且不能跟其他界面自由切换)。
这里面的进度条和我们开发web前端还不一样。我们知道js里,当我们弹出个进度框后,后面代码是可以执行的。在这里不行。
如果我们想用模态方式弹出框,同时还想执行后面代码。这种想法是实现不了了。只有一种办法(至少我这么认为)。将逻辑部份和组件放在一起,同时使用线程去更新UI。

实现

这里以下载文件,同时显示进度条的功能为例。

新建一个windows窗体组件,名字为DownLoadingForm
LabelProgressBar组件到窗体里。如下

在这里插入图片描述

去掉头部的按钮(包括最大/最小/关闭按钮):将窗体的FormBorderStyle设为None
代码如下:

  1. using DongliCAD.utils;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Data;
  6. using System.Drawing;
  7. using System.Linq;
  8. using System.Text;
  9. using System.Threading;
  10. using System.Threading.Tasks;
  11. using System.Windows.Forms;
  12. namespace DongliCAD.component.common
  13. {
  14. public partial class DownLoadingForm : Form
  15. {
  16. private string downUrl;
  17. private string savePath;
  18. /// <summary>
  19. ///
  20. /// </summary>
  21. /// <param name="downUrl">下载url</param>
  22. /// <param name="savePath">本地保存路径</param>
  23. public DownLoadingForm(string downUrl, string savePath)
  24. {
  25. this.downUrl = downUrl;
  26. this.savePath = savePath;
  27. InitializeComponent();
  28. }
  29. /// <summary>
  30. /// 启动线程
  31. /// </summary>
  32. private void startThread()
  33. {
  34. //重新开一个线程用于更新UI
  35. ThreadStart ts = new ThreadStart(startTime);
  36. Thread thread = new Thread(ts);
  37. thread.Name = "startTime";
  38. thread.Start();
  39. }
  40. private System.Timers.Timer aTimer;
  41. /// <summary>
  42. /// 定时器
  43. /// </summary>
  44. private void startTime()
  45. {
  46. aTimer = new System.Timers.Timer();
  47. aTimer.Elapsed += new System.Timers.ElapsedEventHandler(aTimer_Elapsed);
  48. // 设置引发时间的时间间隔 此处设置为1秒
  49. aTimer.Interval = 1000;
  50. aTimer.Enabled = true;
  51. //HttpDownUtil是我的下载类。
  52. string resultPath = HttpDownUtil.HttpDownloadFile(downUrl, savePath);
  53. if (!string.IsNullOrEmpty(resultPath))
  54. {
  55. CloseTime();
  56. }
  57. }
  58. private delegate void SetProgressBarC(string str);
  59. private void aTimer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
  60. {
  61. progressBar.Invoke(new EventHandler(delegate {
  62. if (null != progressBar)
  63. {
  64. int currentValue = progressBar.Value;
  65. currentValue += NumberUtil.getRandNum();
  66. currentValue = currentValue >= 98 ? 98 : currentValue;
  67. progressBar.Value = currentValue;
  68. progressLbl.Text = "下载CAD文件进度:" + currentValue + "%";
  69. if (progressBar.Value >= 100)
  70. {
  71. if(null != aTimer) {
  72. aTimer.Enabled = false;
  73. aTimer.Close();
  74. }
  75. }
  76. }
  77. }
  78. ));
  79. }
  80. public void CloseTime()
  81. {
  82. if (null != aTimer)
  83. {
  84. aTimer.Enabled = false;
  85. aTimer.Close();
  86. }
  87. progressBar.Invoke(new EventHandler(delegate {
  88. if (null != progressBar)
  89. {
  90. int currentValue = 100;
  91. progressBar.Value = currentValue;
  92. progressLbl.Text = "下载CAD文件进度:" + currentValue + "%";
  93. Thread.Sleep(1000);
  94. this.Close();
  95. }
  96. }
  97. ));
  98. }
  99. private void DownLoadingForm_Load(object sender, EventArgs e)
  100. {
  101. //组件初始化完成,启动线程
  102. startThread();
  103. }
  104. }
  105. }

其中注意下载方法HttpDownUtil.HttpDownloadFile也必需放在新线程里执行。这里我只用了假的进度条,真实的太复杂

HttpDownUtil.csHttpDownloadFile方法:

  1. /// <summary>
  2. /// 同步下载
  3. /// Http下载文件
  4. /// </summary>
  5. public static string HttpDownloadFile(string url, string path)
  6. {
  7. // 设置参数
  8. HttpWebRequest request = WebRequest.Create(url) as HttpWebRequest;
  9. if (GlobalData.Authorization.Length > 0)
  10. {
  11. request.Headers.Add("Authorization", GlobalData.Authorization);
  12. }
  13. //发送请求并获取相应回应数据
  14. HttpWebResponse response = request.GetResponse() as HttpWebResponse;
  15. //直到request.GetResponse()程序才开始向目标网页发送Post请求
  16. Stream responseStream = response.GetResponseStream();
  17. //创建本地文件写入流
  18. Stream stream = new FileStream(path, FileMode.Create);
  19. byte[] bArr = new byte[1024];
  20. int size = responseStream.Read(bArr, 0, (int)bArr.Length);
  21. while (size > 0)
  22. {
  23. stream.Write(bArr, 0, size);
  24. size = responseStream.Read(bArr, 0, (int)bArr.Length);
  25. }
  26. stream.Close();
  27. responseStream.Close();
  28. return path;
  29. }

结果

结果如下:
在这里插入图片描述


补充

上面的下载是同步下载,如果在实时显示下载进度需要异常下载。下面代码是实时显示下载进度的代码。

  1. /// <summary>
  2. /// 下载请求信息
  3. /// </summary>
  4. public class DownloadTmp
  5. {
  6. /// <summary>
  7. /// 文件名
  8. /// </summary>
  9. public string fileName;
  10. /// <summary>
  11. /// 下载路径
  12. /// </summary>
  13. public string filePath;
  14. /// <summary>
  15. /// 下载进度回调
  16. /// </summary>
  17. public Action<int> loadingCallback;
  18. /// <summary>
  19. /// 完成回调
  20. /// </summary>
  21. public Action succeedCallback;
  22. /// <summary>
  23. /// 失败回调
  24. /// </summary>
  25. public Action failedCallback;
  26. /// <summary>
  27. /// webRequest
  28. /// </summary>
  29. public HttpWebRequest webRequest;
  30. public long AllContentLength;
  31. public long currentContentLength;
  32. }
  33. using DongliCAD.utils;
  34. using System;
  35. using System.Collections.Generic;
  36. using System.ComponentModel;
  37. using System.Data;
  38. using System.Diagnostics;
  39. using System.Drawing;
  40. using System.IO;
  41. using System.Linq;
  42. using System.Net;
  43. using System.Text;
  44. using System.Threading;
  45. using System.Threading.Tasks;
  46. using System.Windows.Forms;
  47. namespace DongliCAD.component.common
  48. {
  49. public partial class DownLoadingForm : Form
  50. {
  51. private string downUrl;
  52. private string savePath;
  53. private DownloadTmp downloadTmp;
  54. /// <summary>
  55. ///
  56. /// </summary>
  57. /// <param name="downUrl">下载url</param>
  58. /// <param name="savePath">本地保存路径</param>
  59. public DownLoadingForm(string downUrl, string savePath)
  60. {
  61. this.downUrl = downUrl;
  62. this.savePath = savePath;
  63. InitializeComponent();
  64. }
  65. /// <summary>
  66. /// 启动线程
  67. /// </summary>
  68. private void startThread()
  69. {
  70. downloadTmp = new DownloadTmp();
  71. downloadTmp.filePath = savePath;
  72. HttpDownloadZip(downUrl, ref downloadTmp);
  73. //HttpDownUtil.HttpDownloadFile("http://192.168.1.243:85/api/files/download/516610289672650758", savePath);
  74. }
  75. private void DownLoadingForm_Load(object sender, EventArgs e)
  76. {
  77. //组件初始化完成,启动线程
  78. startThread();
  79. }
  80. private void updateProgressBar(long allContentLength, long currentContentLength)
  81. {
  82. Debug.Write("allContentLength: " + allContentLength + ",currentContentLength: " + currentContentLength);
  83. progressBar.Invoke(new EventHandler(delegate {
  84. if (null != progressBar)
  85. {
  86. int step = Convert.ToInt32(currentContentLength * 100 / allContentLength);
  87. progressBar.Value = step;
  88. progressLbl.Text = "下载CAD文件进度:" + step + "%";
  89. }
  90. }
  91. ));
  92. }
  93. /// <summary>
  94. /// 异步回调
  95. /// </summary>
  96. /// <param name="result">Result.</param>
  97. private void BeginResponseCallback(IAsyncResult result)
  98. {
  99. DownloadTmp downloadInfo = (DownloadTmp)result.AsyncState;
  100. HttpWebRequest Request = downloadInfo.webRequest;
  101. HttpWebResponse Response = (HttpWebResponse)Request.EndGetResponse(result);
  102. if (Response.StatusCode == HttpStatusCode.OK || Response.StatusCode == HttpStatusCode.Created)
  103. {
  104. string filePath = downloadInfo.filePath;
  105. if (File.Exists(filePath))
  106. {
  107. File.Delete(filePath);
  108. }
  109. //FileStream fs = new FileStream(filePath, FileMode.Create, FileAccess.Write);
  110. FileStream fs = File.OpenWrite(filePath);
  111. Stream stream = Response.GetResponseStream();
  112. int count = 0;
  113. int num = 0;
  114. long AllContentLength = Response.ContentLength;
  115. long currentContentLength = 0;
  116. if (Response.ContentLength > 0)
  117. {
  118. var buffer = new byte[2048 * 100];
  119. do
  120. {
  121. num++;
  122. count = stream.Read(buffer, 0, buffer.Length);
  123. currentContentLength += count;
  124. updateProgressBar(AllContentLength, currentContentLength);
  125. fs.Write(buffer, 0, count);
  126. if (downloadInfo.loadingCallback != null)
  127. {
  128. float pro = (float)fs.Length / Response.ContentLength * 100;
  129. downloadInfo.loadingCallback((int)pro);
  130. }
  131. } while (count > 0);
  132. }
  133. fs.Close();
  134. Response.Close();
  135. if (downloadInfo.succeedCallback != null)
  136. {
  137. downloadInfo.succeedCallback();
  138. }
  139. progressBar.Invoke(new EventHandler(delegate {
  140. this.Close();
  141. this.DialogResult = DialogResult.OK;
  142. }));
  143. }
  144. else
  145. {
  146. Response.Close();
  147. if (downloadInfo.failedCallback != null)
  148. {
  149. downloadInfo.failedCallback();
  150. }
  151. progressBar.Invoke(new EventHandler(delegate {
  152. this.Close();
  153. this.DialogResult = DialogResult.Cancel;
  154. }));
  155. }
  156. }
  157. /// <summary>
  158. /// 下载文件,异步
  159. /// </summary>
  160. /// <param name="URL">下载路径</param>
  161. /// <param name="downloadPath">文件下载路径</param>
  162. /// <returns></returns>
  163. public void HttpDownloadZip(string URL, ref DownloadTmp downloadInfo)
  164. {
  165. HttpWebRequest request = (HttpWebRequest)WebRequest.Create(URL);
  166. if (GlobalData.Authorization.Length > 0)
  167. {
  168. request.Headers.Add("Authorization", GlobalData.Authorization);
  169. }
  170. downloadInfo.webRequest = request;
  171. request.BeginGetResponse(BeginResponseCallback, downloadInfo);
  172. }
  173. }
  174. }

-———————补充2019-01-22————————-

BackgroundWorker方式

使用BackgroundWorker做成一个上传进度条,外部传入进度值显示,对,就是和你心里想的一样的进度条。

  1. 拖拽一个BackgroundWorker到需要弹出进度条框的窗体上。
    添加代码如下

    private void BackgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)

    1. {
    2. if (e.Error != null)
    3. {
    4. MessageBox.Show(e.Error.Message);
    5. }
    6. else if (e.Cancelled)
    7. {
    8. }
    9. else
    10. {
    11. }
    12. }
    13. private void BackgroundWorker1_DoWork(object sender, DoWorkEventArgs e)
    14. {
    15. startAssembly();
    16. }
    17. private void startAssembly()
    18. {
    19. //导出pdf
    20. this.backgroundWorker1.ReportProgress(20, "正在导出PDF...(1/6)");
    21. this.xExportPDF(this);
    22. Boolean result = false;
    23. this.backgroundWorker1.ReportProgress(30, "正在签出...(2/6)");
    24. result = this.CheckOut();
    25. this.backgroundWorker1.ReportProgress(40, "正在保存图纸...(3/6)");
    26. result = this.DoSaveTitleWBaseInfo();
    27. if (!result)
    28. {
    29. return;
    30. }
    31. this.SaveWorkspaceCadInfoVo();
    32. this.backgroundWorker1.ReportProgress(60, "正在保存BOM...(4/6)");
    33. result = this.SaveBom();
    34. if (!result)
    35. {
    36. return;
    37. }
    38. this.backgroundWorker1.ReportProgress(80, "正在签入...(5/6)");
    39. this.CheckIn();
    40. closeTimeout();
    41. this.backgroundWorker1.ReportProgress(100, "保存成功...(6/6)");
    42. }
  2. 新建一个进度条窗体,包括一个ProgressBar和一个显示文件Label,代码如下

    public partial class UploadLoadingWorkerForm : Form

    1. {
    2. private BackgroundWorker backgroundWorker;
    3. /// <summary>
    4. ///
    5. /// </summary>
    6. public UploadLoadingWorkerForm(BackgroundWorker backgroundWorker)
    7. {
    8. InitializeComponent();
    9. GlobalData.SetAutoScaleMode(this);
    10. this.backgroundWorker = backgroundWorker;
    11. this.backgroundWorker.ProgressChanged += new ProgressChangedEventHandler(backgroundWorker1_ProgressChanged);
    12. this.backgroundWorker.RunWorkerCompleted += new RunWorkerCompletedEventHandler(backgroundWorker1_RunWorkerCompleted);
    13. }
    14. private void backgroundWorker1_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
    15. {
    16. this.DialogResult = DialogResult.OK;
    17. this.Close();//执行完之后,直接关闭页面
    18. }
    19. private void backgroundWorker1_ProgressChanged(object sender, ProgressChangedEventArgs e)
    20. {
    21. this.progressBar.Value = e.ProgressPercentage;
    22. this.progressLbl.Text = e.UserState.ToString();
    23. }

最主要的是backgroundWorker1_ProgressChanged事件处理函数,外部通过 this.backgroundWorker1.ReportProgress(30, “正在签出…(2/6)”);传值,事件处理函数负责接收并显示进度和文本。

  1. 弹出进度条

    UploadLoadingWorkerForm uploadLoadingForm = new UploadLoadingWorkerForm ();
    this.backgroundWorker1.RunWorkerAsync(); // 运行 backgroundWorker 组件
    uploadLoadingForm = new UploadLoadingWorkerForm(this.backgroundWorker1);

发表评论

表情:
评论列表 (有 0 条评论,524人围观)

还没有评论,来说两句吧...

相关阅读