ProgressHelper.cs 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. using PTMedicalInsurance.Variables;
  2. using System;
  3. using System.Collections.Generic;
  4. using System.ComponentModel;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. using System.Windows.Forms;
  9. namespace PTMedicalInsurance.Common
  10. {
  11. public class ProgressDialog : Form
  12. {
  13. private ProgressBar progressBar1;
  14. private Label labelStatus;
  15. private Button cancelButton;
  16. BackgroundWorker _backgroundWorker;
  17. private int maximum;
  18. private ProgressBarStyle _pbStyle = ProgressBarStyle.Marquee;
  19. private string _header = "正在查询...";
  20. private int _marqueeAnimationSpeed = 50;
  21. public string HeaderText
  22. {
  23. get { return _header; }
  24. set { this.Text =_header = value; }
  25. }
  26. public ProgressBarStyle PBStyle
  27. {
  28. get { return _pbStyle; }
  29. set { progressBar1.Style =_pbStyle = value; }
  30. }
  31. public int MQSpeed
  32. {
  33. get { return _marqueeAnimationSpeed; }
  34. set { progressBar1.MarqueeAnimationSpeed =_marqueeAnimationSpeed = value; }
  35. }
  36. public ProgressDialog()
  37. {
  38. Init();
  39. }
  40. public ProgressDialog(BackgroundWorker backgroundWorker)
  41. {
  42. Init();
  43. _backgroundWorker = backgroundWorker;
  44. }
  45. private void Init()
  46. {
  47. Application.EnableVisualStyles();
  48. this.Text = _header;
  49. this.StartPosition = FormStartPosition.CenterParent;
  50. this.FormBorderStyle = FormBorderStyle.FixedDialog;
  51. this.MaximizeBox = false;
  52. this.MinimizeBox = false;
  53. this.ShowInTaskbar = false;
  54. this.TopMost = true; // 确保进度条始终在最前面
  55. this.CenterToScreen();
  56. progressBar1 = new ProgressBar
  57. {
  58. Location = new System.Drawing.Point(12, 12),
  59. Size = new System.Drawing.Size(260, 23)
  60. };
  61. //progressBar1.Style = ProgressBarStyle.Continuous;
  62. progressBar1.Style = _pbStyle;
  63. progressBar1.MarqueeAnimationSpeed = _marqueeAnimationSpeed;
  64. Controls.Add(progressBar1);
  65. labelStatus = new Label
  66. {
  67. Location = new System.Drawing.Point(12, 41),
  68. Size = new System.Drawing.Size(260, 23)
  69. };
  70. Controls.Add(labelStatus);
  71. //// 初始化取消按钮
  72. //cancelButton = new Button
  73. //{
  74. // Text = "取消",
  75. // Location = new System.Drawing.Point(197, 41), // 设置适当的位置
  76. // Size = new System.Drawing.Size(75, 23) // 设置按钮大小
  77. //};
  78. //cancelButton.Click += CancelButton_Click; // 添加点击事件处理程序
  79. //Controls.Add(cancelButton);
  80. // 初始化取消按钮
  81. cancelButton = new Button
  82. {
  83. Text = "取消",
  84. Location = new System.Drawing.Point(197, 60), // 修改Y坐标以避免与labelStatus重叠
  85. Size = new System.Drawing.Size(75, 23) // 设置按钮大小
  86. };
  87. cancelButton.Click += CancelButton_Click; // 添加点击事件处理程序
  88. Controls.Add(cancelButton);
  89. // 设置默认样式
  90. SetStyle(ControlStyles.ResizeRedraw, true);
  91. ClientSize = new System.Drawing.Size(284, 100);
  92. }
  93. // 允许外部设置进度条的值
  94. public int ProgressValue
  95. {
  96. set { if (InvokeRequired) Invoke(new Action(() => progressBar1.Value = value)); else progressBar1.Value = value; }
  97. }
  98. public void UpdateProgress(int progress)
  99. {
  100. //if (progressBar1.InvokeRequired)
  101. //{
  102. // progressBar1.Invoke(new Action<int>(UpdateProgress), progress);
  103. //}
  104. //else
  105. //{
  106. // progressBar1.Value = progress;
  107. // //这个有点糊涂了,这个进度条显示总是少一个
  108. // labelStatus.Text = $"已完成 {progress}/{maximum}";
  109. //}
  110. this.Invoke((MethodInvoker)delegate
  111. {
  112. progressBar1.Value = progress;
  113. //这个有点糊涂了,这个进度条显示总是少一个
  114. labelStatus.Text = $"已完成 {progress}/{maximum}";
  115. ///在Windows Forms应用程序中,控件的更新通常是由操作系统消息循环处理的。当你修改一个控件的属性(如 Text 或 Value),
  116. ///这些更改并不会立即反映在界面上,而是会被放入队列等待下一个合适的时机进行绘制。这是因为直接更新控件属性并不会强制执行重绘操作,
  117. ///系统可能会批量处理多个更新以提高效率。
  118. ///使用 Refresh() 方法 调用控件的 Refresh() 方法会强制该控件立即重绘自身。这包括清除控件并重新绘制其所有内容
  119. if (progress == maximum)
  120. {
  121. progressBar1.Refresh();
  122. labelStatus.Refresh();
  123. }
  124. });
  125. }
  126. public void SetProgress(int max)
  127. {
  128. maximum = max;
  129. progressBar1.Maximum = maximum;
  130. }
  131. // 允许外部设置状态文本
  132. public string StatusText
  133. {
  134. set { if (InvokeRequired) Invoke(new Action(() => labelStatus.Text = value)); else labelStatus.Text = value; }
  135. }
  136. //异步展示
  137. public async void ShowAsync()
  138. {
  139. await Task.Run(() => progressBar1.Show());
  140. }
  141. private void CancelButton_Click(object sender, EventArgs e)
  142. {
  143. // 这里可以放置取消操作的逻辑
  144. // 比如通知BackgroundWorker取消工作
  145. if (_backgroundWorker != null && _backgroundWorker.WorkerSupportsCancellation)
  146. {
  147. _backgroundWorker.CancelAsync();
  148. }
  149. this.Close(); // 关闭对话框
  150. }
  151. }
  152. public class DataLoader : IDisposable
  153. {
  154. private BackgroundWorker _backgroundWorker = new BackgroundWorker();
  155. public delegate int MyFunc<T1>(out T1 err,ProgressCallback progressCallback);
  156. private MyFunc<string> _delegateFunc;
  157. private ProgressDialog progressDialog ;
  158. private Form mainForm;
  159. // 定义进度回调委托
  160. public delegate void ProgressCallback(int progress);
  161. public DataLoader(MyFunc<string> delegateFunc, Form frm)
  162. {
  163. mainForm = frm;
  164. _delegateFunc = delegateFunc ?? throw new ArgumentNullException(nameof(delegateFunc));
  165. // 配置 BackgroundWorker
  166. _backgroundWorker.WorkerReportsProgress = true;
  167. _backgroundWorker.WorkerSupportsCancellation = true;
  168. _backgroundWorker.DoWork += BackgroundWorker_DoWork;
  169. _backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
  170. _backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
  171. progressDialog = new ProgressDialog(_backgroundWorker);
  172. }
  173. public DataLoader(Form frm)
  174. {
  175. mainForm = frm;
  176. // 配置 BackgroundWorker
  177. _backgroundWorker.WorkerReportsProgress = true;
  178. _backgroundWorker.WorkerSupportsCancellation = true;
  179. _backgroundWorker.DoWork += BackgroundWorker_DoWork;
  180. _backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
  181. _backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
  182. progressDialog = new ProgressDialog(_backgroundWorker);
  183. }
  184. public void SetDelagate(MyFunc<string> delegateFunc)
  185. {
  186. _delegateFunc = delegateFunc ?? throw new ArgumentNullException(nameof(delegateFunc));
  187. }
  188. public void SetProgressBar(ProgressBarStyle pbStyle,string headerText,int mqSpeed)
  189. {
  190. progressDialog.PBStyle = pbStyle;
  191. progressDialog.HeaderText = headerText;
  192. progressDialog.MQSpeed = mqSpeed;
  193. }
  194. public void StartQueryExportData(int total, Action<int, string> onCompleted)
  195. {
  196. if (mainForm == null)
  197. {
  198. progressDialog.Show();
  199. }
  200. else
  201. {
  202. progressDialog.Show(mainForm);
  203. }
  204. if (_backgroundWorker.IsBusy) return;
  205. this._onCompleted = onCompleted;
  206. _backgroundWorker.RunWorkerAsync(total);
  207. }
  208. private Action<int, string> _onCompleted;
  209. private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
  210. {
  211. // 调用传入的方法
  212. string errMsg = "";
  213. int result = -1;
  214. int total = (int)e.Argument; // 获取传入的总项目数
  215. if (total > 0)
  216. {
  217. progressDialog.SetProgress(total);
  218. //注意,如果_queryExportDataAction 事件里需要更新UI 必须使用 Control.Invoke 或 Control.BeginInvoke。否则会导致程序卡死
  219. ///类似这样:this.Invoke((MethodInvoker)delegate {labelProgress.Text = $"Progress: {progress}%"; });
  220. result = _delegateFunc(out errMsg, (progress) =>
  221. {
  222. if (!_backgroundWorker.CancellationPending)
  223. {
  224. _backgroundWorker.ReportProgress(progress);
  225. }
  226. else
  227. {
  228. // 如果用户请求了取消,则跳出循环或采取其他措施
  229. // 这个异常处理查询下
  230. throw new OperationCanceledException();
  231. }
  232. });
  233. }
  234. else
  235. {
  236. result = _delegateFunc(out errMsg, (progress) => { });
  237. }
  238. e.Result = Tuple.Create(result, errMsg);
  239. }
  240. private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  241. {
  242. if (!_backgroundWorker.CancellationPending)
  243. {
  244. System.Threading.Thread.Sleep(1000);
  245. }
  246. progressDialog.Close();
  247. if (e.Error != null)
  248. {
  249. // 处理错误
  250. MessageBox.Show($"An error occurred: {e.Error.Message}");
  251. }
  252. else if (e.Cancelled)
  253. {
  254. // 处理取消的情况
  255. MessageBox.Show("Operation was cancelled.");
  256. }
  257. else
  258. {
  259. var resultTuple = (Tuple<int, string>)e.Result;
  260. int result = resultTuple.Item1;
  261. string errMsg = resultTuple.Item2;
  262. // 调用回调函数,传递结果和错误信息
  263. _onCompleted?.Invoke(result, errMsg);
  264. }
  265. Dispose();
  266. }
  267. private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
  268. {
  269. progressDialog.UpdateProgress(e.ProgressPercentage );
  270. }
  271. public void Dispose()
  272. {
  273. _backgroundWorker.Dispose();
  274. progressDialog.Dispose();
  275. }
  276. }
  277. }