ProgressWrapper.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380
  1. using Org.BouncyCastle.Asn1.Crmf;
  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 static System.Net.Mime.MediaTypeNames;
  9. using System.Windows.Forms;
  10. using System.Drawing;
  11. namespace PTMedicalInsurance.Helper
  12. {
  13. [DesignerCategory("Code")]
  14. public class ProgressDialog : Form
  15. {
  16. private ProgressBar _progressBar;
  17. private Label _labelStatus;
  18. private Button _cancelButton;
  19. private BackgroundWorker _backgroundWorker;
  20. private int _maximum = 100;
  21. private string _header = "正在查询...";
  22. public string HeaderText
  23. {
  24. get => _header;
  25. set { Text = _header = value; }
  26. }
  27. public ProgressBarStyle PBStyle
  28. {
  29. get => _progressBar.Style;
  30. set => _progressBar.Style = value;
  31. }
  32. public int MQSpeed
  33. {
  34. get => _progressBar.MarqueeAnimationSpeed;
  35. set => _progressBar.MarqueeAnimationSpeed = value;
  36. }
  37. public ProgressDialog()
  38. {
  39. InitComponent();
  40. }
  41. public ProgressDialog(BackgroundWorker backgroundWorker) : this()
  42. {
  43. _backgroundWorker = backgroundWorker;
  44. }
  45. public void InitComponent()
  46. {
  47. System.Windows.Forms.Application.EnableVisualStyles();
  48. // 设置窗体样式
  49. Text = _header;
  50. StartPosition = FormStartPosition.CenterParent;
  51. FormBorderStyle = FormBorderStyle.FixedDialog;
  52. MaximizeBox = false;
  53. MinimizeBox = false;
  54. ShowInTaskbar = false;
  55. TopMost = true;
  56. ClientSize = new Size(800, 100);
  57. CenterToScreen();
  58. // 初始化进度条
  59. _progressBar = new ProgressBar
  60. {
  61. Location = new Point(12, 12),
  62. Size = new Size(700, 23),
  63. Style = ProgressBarStyle.Marquee,
  64. MarqueeAnimationSpeed = 50
  65. };
  66. Controls.Add(_progressBar);
  67. // 状态标签
  68. _labelStatus = new Label
  69. {
  70. Location = new Point(12, 41),
  71. Size = new Size(360, 23)
  72. };
  73. Controls.Add(_labelStatus);
  74. // 取消按钮
  75. _cancelButton = new Button
  76. {
  77. Text = "取消",
  78. Location = new Point(520, 60),
  79. Size = new Size(75, 23)
  80. };
  81. _cancelButton.Click += CancelButton_Click;
  82. Controls.Add(_cancelButton);
  83. SetStyle(ControlStyles.ResizeRedraw, true);
  84. }
  85. public int ProgressValue
  86. {
  87. set
  88. {
  89. if (this.IsHandleCreated)
  90. {
  91. this.InvokeIfRequired(() =>
  92. {
  93. _progressBar.Value = value;
  94. _labelStatus.Text = $"已完成 {value}/{_maximum}";
  95. if (value == _maximum || value >= _progressBar.Maximum)
  96. {
  97. _progressBar.Refresh();
  98. _labelStatus.Refresh();
  99. }
  100. });
  101. }
  102. }
  103. }
  104. public void SetProgress(int max)
  105. {
  106. _maximum = max;
  107. _progressBar.Maximum = max;
  108. }
  109. public string StatusText
  110. {
  111. set => this.InvokeIfRequired(() => _labelStatus.Text = value);
  112. }
  113. private void CancelButton_Click(object sender, EventArgs e)
  114. {
  115. if (_backgroundWorker != null && _backgroundWorker.WorkerSupportsCancellation)
  116. {
  117. _backgroundWorker.CancelAsync();
  118. }
  119. this.Close();
  120. }
  121. public async void ShowAsync()
  122. {
  123. await Task.Run(() =>
  124. {
  125. System.Windows.Forms.Application.Run(this);
  126. });
  127. }
  128. protected override void OnClosed(EventArgs e)
  129. {
  130. base.OnClosed(e);
  131. _backgroundWorker = null;
  132. }
  133. }
  134. public static class ControlExtensions
  135. {
  136. public static void InvokeIfRequired(this Control control, MethodInvoker action)
  137. {
  138. if (control.InvokeRequired)
  139. {
  140. try
  141. {
  142. control.Invoke(action);
  143. }
  144. catch (Exception ex) when (ex is InvalidOperationException || ex is InvalidAsynchronousStateException)
  145. {
  146. // 忽略无效句柄操作
  147. Console.WriteLine("无法执行 Invoke:" + ex.Message);
  148. }
  149. }
  150. else
  151. {
  152. action();
  153. }
  154. }
  155. }
  156. public class DataLoaderContext
  157. {
  158. //
  159. public object[] args { get; set; } //入参
  160. // 回调函数(替代委托参数)
  161. public delegate void ProgressCallback(int progress);
  162. public delegate void ProgressMaxCallback(int max);
  163. public ProgressCallback reportProgress { get; set; }
  164. public delegate void SetProgressMaximum(int max); // 最大值
  165. public ProgressMaxCallback setProgressMaximum { get; set; }
  166. public delegate void SetProgressHeaderText(ProgressBarStyle progressBarStyle, string content, int speed);
  167. public SetProgressHeaderText setProgressHeaderText { get; set; }
  168. public Action<int, string> OnCompleted { get; set; } // 完成回调(可选)
  169. // 取消支持
  170. public BackgroundWorker Worker { get; set; } // 用于取消检查
  171. }
  172. class ProgressWrapper
  173. {
  174. private readonly BackgroundWorker _backgroundWorker;
  175. private ProgressDialog _progressDialog;
  176. private readonly Form _ownerForm;
  177. public delegate int MyFunc<T>(DataLoaderContext context, out T err);
  178. private readonly MyFunc<string> _delegateFunc;
  179. private Action<int, string> _onCompleted;
  180. private bool _disposed = false;
  181. public delegate void ProgressCallback(int progress);
  182. public delegate void ProgressMaxCallback(int max);
  183. public ProgressWrapper(MyFunc<string> func, Form ownerForm)
  184. {
  185. _delegateFunc = func ?? throw new ArgumentNullException(nameof(func));
  186. _ownerForm = ownerForm;
  187. _backgroundWorker = new BackgroundWorker
  188. {
  189. WorkerReportsProgress = true,
  190. WorkerSupportsCancellation = true
  191. };
  192. _backgroundWorker.DoWork += BackgroundWorker_DoWork;
  193. _backgroundWorker.ProgressChanged += BackgroundWorker_ProgressChanged;
  194. _backgroundWorker.RunWorkerCompleted += BackgroundWorker_RunWorkerCompleted;
  195. }
  196. public void SetProgressBar(ProgressBarStyle style, string headerText, int mqSpeed)
  197. {
  198. if (_progressDialog == null || _progressDialog.IsDisposed)
  199. {
  200. _progressDialog = new ProgressDialog(_backgroundWorker)
  201. {
  202. PBStyle = style,
  203. HeaderText = headerText,
  204. MQSpeed = mqSpeed
  205. };
  206. }
  207. else
  208. {
  209. if (mqSpeed < 0) mqSpeed = 50;
  210. _progressDialog.PBStyle = style;
  211. _progressDialog.HeaderText = headerText;
  212. _progressDialog.MQSpeed = mqSpeed;
  213. }
  214. }
  215. public void Start(object[] args, Action<int, string> onCompleted)
  216. {
  217. if (_backgroundWorker.IsBusy) return;
  218. _onCompleted = onCompleted;
  219. if (_ownerForm == null || _ownerForm.IsDisposed)
  220. {
  221. _progressDialog?.Show();
  222. }
  223. else
  224. {
  225. _progressDialog?.Show(_ownerForm);
  226. }
  227. _backgroundWorker.RunWorkerAsync(args);
  228. }
  229. private void BackgroundWorker_DoWork(object sender, DoWorkEventArgs e)
  230. {
  231. var worker = sender as BackgroundWorker;
  232. if (worker == null)
  233. {
  234. e.Result = Tuple.Create(-1, "BackgroundWorker 实例无效");
  235. return;
  236. }
  237. var _args = e.Argument as object[];
  238. if (_args == null || _args.Length == 0)
  239. {
  240. e.Result = Tuple.Create(-1, "参数无效");
  241. return;
  242. }
  243. string errMsg = "";
  244. int result = -1;
  245. try
  246. {
  247. DataLoaderContext context = new DataLoaderContext();
  248. context.Worker = _backgroundWorker;
  249. context.args = _args;
  250. // 定义进度报告的 Action
  251. DataLoaderContext.ProgressCallback _reportProgress = percent =>
  252. {
  253. if (worker.WorkerReportsProgress && !worker.CancellationPending)
  254. worker.ReportProgress(percent);
  255. };
  256. // 定义设置最大值的 Action
  257. DataLoaderContext.ProgressMaxCallback _setProgressMax = max =>
  258. {
  259. if (_progressDialog != null && !_progressDialog.IsDisposed)
  260. _progressDialog.SetProgress(max);
  261. };
  262. // 设置标题
  263. DataLoaderContext.SetProgressHeaderText _setProgressHeader = (progressBarStyle, header, speed) =>
  264. {
  265. if (_progressDialog != null && !_progressDialog.IsDisposed)
  266. SetProgressBar(progressBarStyle, header, speed);
  267. };
  268. context.reportProgress = _reportProgress;
  269. context.setProgressMaximum = _setProgressMax;
  270. context.setProgressHeaderText = _setProgressHeader;
  271. context.Worker = _backgroundWorker;
  272. // 调用实际业务逻辑
  273. result = _delegateFunc(context, out errMsg);
  274. }
  275. catch (Exception ex)
  276. {
  277. errMsg = $"后台任务发生异常: {ex.Message}";
  278. result = 0;
  279. }
  280. // 返回结果给 RunWorkerCompleted 事件
  281. e.Result = Tuple.Create(result, errMsg);
  282. }
  283. private void BackgroundWorker_ProgressChanged(object sender, ProgressChangedEventArgs e)
  284. {
  285. //_progressDialog?.UpdateProgress(e.ProgressPercentage);
  286. _progressDialog.ProgressValue = (e.ProgressPercentage);
  287. }
  288. private void BackgroundWorker_RunWorkerCompleted(object sender, RunWorkerCompletedEventArgs e)
  289. {
  290. if (e.Cancelled)
  291. {
  292. MessageBox.Show("操作已取消");
  293. }
  294. else if (e.Error != null)
  295. {
  296. MessageBox.Show($"发生错误:{e.Error.Message}");
  297. }
  298. else
  299. {
  300. var resultTuple = (Tuple<int, string>)e.Result;
  301. _onCompleted?.Invoke(resultTuple.Item1, resultTuple.Item2);
  302. }
  303. _progressDialog?.Close();
  304. _progressDialog?.Dispose();
  305. _progressDialog = null;
  306. }
  307. #region IDisposable Support
  308. protected virtual void Dispose(bool disposing)
  309. {
  310. if (!_disposed)
  311. {
  312. if (disposing)
  313. {
  314. _backgroundWorker.Dispose();
  315. _progressDialog?.Dispose();
  316. }
  317. _disposed = true;
  318. }
  319. }
  320. public void Dispose()
  321. {
  322. Dispose(true);
  323. GC.SuppressFinalize(this);
  324. }
  325. #endregion
  326. }
  327. }