WaitHelper.cs 22 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495
  1. using DevExpress.Utils.Drawing;
  2. using DevExpress.Utils.Extensions;
  3. using DevExpress.XtraSplashScreen;
  4. using DevExpress.XtraWaitForm;
  5. using System;
  6. using System.Collections.Generic;
  7. using System.ComponentModel;
  8. using System.Data;
  9. using System.Drawing;
  10. using System.IO;
  11. using System.Linq;
  12. using System.Text;
  13. using System.Threading;
  14. using System.Threading.Tasks;
  15. using System.Windows.Forms;
  16. namespace DxHelper
  17. {
  18. /// <summary>
  19. /// 等待窗体帮助类,包含WaitForm、OverlayForm、
  20. /// </summary>
  21. public static class WaitHelper
  22. {
  23. #region private field
  24. private static IOverlaySplashScreenHandle _handle;
  25. private static OverlayTextPainter _overlayLabel = new OverlayTextPainterEx();
  26. private static List<string> _tips = new List<string>();
  27. private static Random _random = new Random();
  28. private static DateTime _updateTime;
  29. #endregion
  30. #region public function
  31. /// <summary>
  32. /// 显示等待窗体
  33. /// </summary>
  34. /// <param name="title">标题</param>
  35. /// <param name="caption">文本</param>
  36. /// <param name="owner">等待窗体的父窗体,默认值为激活的主程序窗体</param>
  37. public static void ShowWaitForm(string title, string caption, Form owner = null)
  38. {
  39. SplashScreenManager.ShowForm(owner, typeof(MyWaitForm), true, true, false);
  40. SplashScreenManager.Default.SetWaitFormCaption(title);//标题
  41. SplashScreenManager.Default.SetWaitFormDescription(caption);//描述
  42. }
  43. /// <summary>
  44. /// 显示等待窗体(文本固定为请稍后和加载中...)
  45. /// </summary>
  46. /// <param name="owner">等待窗体的父窗体,默认值为激活的主程序窗体</param>
  47. public static void ShowWaitForm(Form owner = null)
  48. {
  49. SplashScreenManager.ShowForm(owner, typeof(MyWaitForm), true, true, false);
  50. SplashScreenManager.Default.SetWaitFormCaption("请稍后");//标题
  51. SplashScreenManager.Default.SetWaitFormDescription("加载中...");//描述
  52. }
  53. /// <summary>
  54. /// 关闭等待窗体和程序启动画面窗体
  55. /// </summary>
  56. public static void CloseForm()
  57. {
  58. SplashScreenManager.CloseForm(false, 0, null);
  59. }
  60. /// <summary>
  61. /// 在某个control上显示半透明遮罩层
  62. /// </summary>
  63. /// <param name="owner">遮罩层覆盖的Control</param>
  64. public static void ShowOverlayForm(Control owner)
  65. {
  66. int opacity = 180;
  67. if (SystemInformation.TerminalServerSession)
  68. opacity = 255; //远程桌面(RDP)下禁用opacity,否则网络可能会卡断
  69. if (owner == null || !owner.Visible) return;
  70. _overlayLabel.Font = new Font(owner.Font.FontFamily, 18);
  71. _overlayLabel.Text = null;
  72. _handle = SplashScreenManager.ShowOverlayForm(owner, opacity: opacity, fadeIn: false, fadeOut: false, customPainter: new OverlayWindowCompositePainter(_overlayLabel));
  73. }
  74. /// <summary>
  75. /// 更新遮罩层上的文本
  76. /// </summary>
  77. /// <param name="text"></param>
  78. public static void UpdateOverlyText(string text)
  79. {
  80. _overlayLabel.Text = text;
  81. }
  82. /// <summary>
  83. /// 关闭上一次显示的半透明遮罩层
  84. /// </summary>
  85. public static void CloseOverlayForm()
  86. {
  87. if (_handle == null) return;
  88. if (!string.IsNullOrWhiteSpace(_overlayLabel.Text))
  89. {
  90. Task.Run(() =>
  91. {
  92. Thread.Sleep(1000);
  93. SplashScreenManager.CloseOverlayForm(_handle);
  94. });
  95. }
  96. else
  97. SplashScreenManager.CloseOverlayForm(_handle);
  98. }
  99. /// <summary>
  100. /// 显示程序启动画面
  101. /// </summary>
  102. public static void ShowSplashScreen(string title, string company)
  103. {
  104. SplashScreenManager.ShowForm(typeof(MySplashScreen)); //调用
  105. SplashScreenManager.Default?.SendCommand(SplashScreenCommand.UpdateTitle, title);
  106. SplashScreenManager.Default?.SendCommand(SplashScreenCommand.UpdateCompany, company);
  107. _updateTime = DateTime.Now;
  108. Task.Run(() =>
  109. {
  110. var tips = _tips.Skip(0).ToList();
  111. while (true)
  112. {
  113. while ((DateTime.Now - _updateTime).TotalMilliseconds < 2000)
  114. {
  115. Thread.Sleep(100);
  116. }
  117. var tipsIdx = _random.Next(0, tips.Count);
  118. var res = UpdateSplashMessage(_tips[tipsIdx]);
  119. if (!res) break;
  120. tips.RemoveAt(tipsIdx);
  121. if (!tips.Any()) break;
  122. }
  123. });
  124. }
  125. /// <summary>
  126. /// 更新启动画面窗体的文本消息
  127. /// </summary>
  128. /// <param name="msg"></param>
  129. /// <returns>如果启动窗体已关闭返回false,否则返回true</returns>
  130. public static bool UpdateSplashMessage(string msg)
  131. {
  132. _updateTime = DateTime.Now;
  133. if (SplashScreenManager.Default == null || !SplashScreenManager.Default.IsSplashFormVisible) return false;
  134. SplashScreenManager.Default?.SendCommand(SplashScreenCommand.UpdateMessage, msg);
  135. return true;
  136. }
  137. public static void SetSplashTips(IEnumerable<string> tips)
  138. {
  139. _tips.Clear();
  140. _tips.AddRange(tips);
  141. }
  142. public static void SetSplashTips(string tipsFile)
  143. {
  144. _tips.Clear();
  145. if (File.Exists(tipsFile))
  146. _tips.AddRange(File.ReadAllLines(tipsFile));
  147. }
  148. #endregion
  149. #region internal class
  150. class OverlayTextPainterEx : OverlayTextPainter
  151. {
  152. protected override Rectangle CalcTextBounds(OverlayLayeredWindowObjectInfoArgs drawArgs)
  153. {
  154. Size textSz = CalcTextSize(drawArgs);
  155. return textSz.AlignWith(drawArgs.Bounds).WithY(drawArgs.ImageBounds.GetCenterPoint().Y - textSz.Height / 2);
  156. }
  157. }
  158. partial class MyWaitForm : WaitForm
  159. {
  160. private Form owner;
  161. public MyWaitForm()
  162. {
  163. InitializeComponent();
  164. this.progressPanel1.AutoHeight = true;
  165. this.StartPosition = FormStartPosition.CenterParent;
  166. }
  167. #region Overrides
  168. public override void SetCaption(string caption)
  169. {
  170. base.SetCaption(caption);
  171. this.progressPanel1.Caption = caption;
  172. }
  173. public override void SetDescription(string description)
  174. {
  175. base.SetDescription(description);
  176. this.progressPanel1.Description = description;
  177. }
  178. public override void ProcessCommand(Enum cmd, object arg)
  179. {
  180. base.ProcessCommand(cmd, arg);
  181. }
  182. #endregion
  183. public enum WaitFormCommand
  184. {
  185. }
  186. public void ShowWaitForm(Form owner, string description, string caption)
  187. {
  188. SplashScreenManager.ShowForm(owner, typeof(WaitHelper), true, true, false);
  189. SplashScreenManager.Default.SetWaitFormDescription(description);//描述
  190. SplashScreenManager.Default.SetWaitFormCaption(caption);//标题
  191. }
  192. public void ShowWaitForm(Form owner)
  193. {
  194. this.owner = owner;
  195. SplashScreenManager.ShowForm(owner, typeof(WaitHelper), true, true, false);
  196. }
  197. public void CloseWaitForm()
  198. {
  199. SplashScreenManager.CloseForm(false, 0, owner);
  200. }
  201. }
  202. partial class MyWaitForm
  203. {
  204. /// <summary>
  205. /// Required designer variable.
  206. /// </summary>
  207. private System.ComponentModel.IContainer components = null;
  208. /// <summary>
  209. /// Clean up any resources being used.
  210. /// </summary>
  211. /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
  212. protected override void Dispose(bool disposing)
  213. {
  214. if (disposing && (components != null))
  215. {
  216. components.Dispose();
  217. }
  218. base.Dispose(disposing);
  219. }
  220. #region Windows Form Designer generated code
  221. /// <summary>
  222. /// Required method for Designer support - do not modify
  223. /// the contents of this method with the code editor.
  224. /// </summary>
  225. private void InitializeComponent()
  226. {
  227. this.progressPanel1 = new DevExpress.XtraWaitForm.ProgressPanel();
  228. this.tableLayoutPanel1 = new System.Windows.Forms.TableLayoutPanel();
  229. this.tableLayoutPanel1.SuspendLayout();
  230. this.SuspendLayout();
  231. //
  232. // progressPanel1
  233. //
  234. this.progressPanel1.Appearance.BackColor = System.Drawing.Color.Transparent;
  235. this.progressPanel1.Appearance.Options.UseBackColor = true;
  236. this.progressPanel1.AppearanceCaption.Font = new System.Drawing.Font("Microsoft Sans Serif", 12F);
  237. this.progressPanel1.AppearanceCaption.Options.UseFont = true;
  238. this.progressPanel1.AppearanceDescription.Font = new System.Drawing.Font("Microsoft Sans Serif", 8.25F);
  239. this.progressPanel1.AppearanceDescription.Options.UseFont = true;
  240. this.progressPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
  241. this.progressPanel1.ImageHorzOffset = 20;
  242. this.progressPanel1.Location = new System.Drawing.Point(0, 17);
  243. this.progressPanel1.Margin = new System.Windows.Forms.Padding(0, 3, 0, 3);
  244. this.progressPanel1.Name = "progressPanel1";
  245. this.progressPanel1.Size = new System.Drawing.Size(246, 39);
  246. this.progressPanel1.TabIndex = 0;
  247. this.progressPanel1.Text = "progressPanel1";
  248. //
  249. // tableLayoutPanel1
  250. //
  251. this.tableLayoutPanel1.AutoSize = true;
  252. this.tableLayoutPanel1.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
  253. this.tableLayoutPanel1.BackColor = System.Drawing.Color.Transparent;
  254. this.tableLayoutPanel1.ColumnCount = 1;
  255. this.tableLayoutPanel1.ColumnStyles.Add(new System.Windows.Forms.ColumnStyle(System.Windows.Forms.SizeType.Percent, 100F));
  256. this.tableLayoutPanel1.Controls.Add(this.progressPanel1, 0, 0);
  257. this.tableLayoutPanel1.Dock = System.Windows.Forms.DockStyle.Fill;
  258. this.tableLayoutPanel1.Location = new System.Drawing.Point(0, 0);
  259. this.tableLayoutPanel1.Name = "tableLayoutPanel1";
  260. this.tableLayoutPanel1.Padding = new System.Windows.Forms.Padding(0, 14, 0, 14);
  261. this.tableLayoutPanel1.RowCount = 1;
  262. this.tableLayoutPanel1.RowStyles.Add(new System.Windows.Forms.RowStyle(System.Windows.Forms.SizeType.Percent, 100F));
  263. this.tableLayoutPanel1.Size = new System.Drawing.Size(246, 73);
  264. this.tableLayoutPanel1.TabIndex = 1;
  265. //
  266. // Form1
  267. //
  268. this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 13F);
  269. this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
  270. this.AutoSize = true;
  271. this.AutoSizeMode = System.Windows.Forms.AutoSizeMode.GrowAndShrink;
  272. this.ClientSize = new System.Drawing.Size(246, 73);
  273. this.Controls.Add(this.tableLayoutPanel1);
  274. this.DoubleBuffered = true;
  275. this.Name = "Form1";
  276. this.StartPosition = System.Windows.Forms.FormStartPosition.Manual;
  277. this.Text = "Form1";
  278. this.tableLayoutPanel1.ResumeLayout(false);
  279. this.ResumeLayout(false);
  280. this.PerformLayout();
  281. }
  282. #endregion
  283. private DevExpress.XtraWaitForm.ProgressPanel progressPanel1;
  284. private System.Windows.Forms.TableLayoutPanel tableLayoutPanel1;
  285. }
  286. partial class MySplashScreen : SplashScreen
  287. {
  288. public MySplashScreen()
  289. {
  290. InitializeComponent();
  291. this.labMsg.Text = "";
  292. peImage.Properties.Appearance.Font = new Font(peImage.Properties.Appearance.Font.FontFamily, 16);
  293. peImage.Properties.NullText = "某系统";
  294. this.labelCopyright.Text = $"Copyright © {DateTime.Now.Year} 总参第五十七研究所";
  295. }
  296. #region Overrides
  297. public override void ProcessCommand(Enum cmd, object arg)
  298. {
  299. var command = (SplashScreenCommand)cmd;
  300. base.ProcessCommand(cmd, arg);
  301. if (command == SplashScreenCommand.UpdateMessage)
  302. {
  303. this.labMsg.Text = arg.ToString();
  304. }
  305. else if (command == SplashScreenCommand.UpdateTitle)
  306. {
  307. peImage.Properties.NullText = arg?.ToString();
  308. }
  309. else if (command == SplashScreenCommand.UpdateCompany && arg != null && !string.IsNullOrWhiteSpace(arg.ToString()))
  310. {
  311. this.labelCopyright.Text = $"Copyright © {DateTime.Now.Year} {arg}";
  312. }
  313. else if (command == SplashScreenCommand.UpdateCompany && (arg == null || string.IsNullOrWhiteSpace(arg.ToString())))
  314. {
  315. this.labelCopyright.Visible = false;
  316. }
  317. }
  318. #endregion
  319. }
  320. enum SplashScreenCommand
  321. {
  322. UpdateMessage,
  323. UpdateTitle,
  324. UpdateCompany
  325. }
  326. partial class MySplashScreen
  327. {
  328. /// <summary>
  329. /// Required designer variable.
  330. /// </summary>
  331. private System.ComponentModel.IContainer components = null;
  332. /// <summary>
  333. /// Clean up any resources being used.
  334. /// </summary>
  335. /// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
  336. protected override void Dispose(bool disposing)
  337. {
  338. if (disposing && (components != null))
  339. {
  340. components.Dispose();
  341. }
  342. base.Dispose(disposing);
  343. }
  344. #region Windows Form Designer generated code
  345. /// <summary>
  346. /// Required method for Designer support - do not modify
  347. /// the contents of this method with the code editor.
  348. /// </summary>
  349. private void InitializeComponent()
  350. {
  351. this.progressBarControl = new DevExpress.XtraEditors.MarqueeProgressBarControl();
  352. this.labelCopyright = new DevExpress.XtraEditors.LabelControl();
  353. this.labMsg = new DevExpress.XtraEditors.LabelControl();
  354. this.peImage = new DevExpress.XtraEditors.PictureEdit();
  355. this.tablePanel1 = new DevExpress.Utils.Layout.TablePanel();
  356. ((System.ComponentModel.ISupportInitialize)(this.progressBarControl.Properties)).BeginInit();
  357. ((System.ComponentModel.ISupportInitialize)(this.peImage.Properties)).BeginInit();
  358. ((System.ComponentModel.ISupportInitialize)(this.tablePanel1)).BeginInit();
  359. this.tablePanel1.SuspendLayout();
  360. this.SuspendLayout();
  361. //
  362. // progressBarControl
  363. //
  364. this.progressBarControl.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
  365. | System.Windows.Forms.AnchorStyles.Right)));
  366. this.progressBarControl.EditValue = 0;
  367. this.progressBarControl.Location = new System.Drawing.Point(24, 230);
  368. this.progressBarControl.Name = "progressBarControl";
  369. this.progressBarControl.Size = new System.Drawing.Size(402, 11);
  370. this.progressBarControl.TabIndex = 5;
  371. //
  372. // labelCopyright
  373. //
  374. this.labelCopyright.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
  375. this.tablePanel1.SetColumn(this.labelCopyright, 1);
  376. this.labelCopyright.Location = new System.Drawing.Point(191, 8);
  377. this.labelCopyright.Name = "labelCopyright";
  378. this.tablePanel1.SetRow(this.labelCopyright, 0);
  379. this.labelCopyright.Size = new System.Drawing.Size(66, 20);
  380. this.labelCopyright.TabIndex = 6;
  381. this.labelCopyright.Text = "Copyright";
  382. //
  383. // labMsg
  384. //
  385. this.labMsg.Location = new System.Drawing.Point(24, 198);
  386. this.labMsg.Margin = new System.Windows.Forms.Padding(3, 3, 3, 1);
  387. this.labMsg.Name = "labMsg";
  388. this.labMsg.Size = new System.Drawing.Size(62, 20);
  389. this.labMsg.TabIndex = 7;
  390. this.labMsg.Text = "Starting...";
  391. //
  392. // peImage
  393. //
  394. this.peImage.Dock = System.Windows.Forms.DockStyle.Top;
  395. this.peImage.Location = new System.Drawing.Point(1, 1);
  396. this.peImage.Name = "peImage";
  397. this.peImage.Properties.AllowFocused = false;
  398. this.peImage.Properties.Appearance.BackColor = System.Drawing.Color.FromArgb(((int)(((byte)(128)))), ((int)(((byte)(128)))), ((int)(((byte)(255)))));
  399. this.peImage.Properties.Appearance.Options.UseBackColor = true;
  400. this.peImage.Properties.BorderStyle = DevExpress.XtraEditors.Controls.BorderStyles.NoBorder;
  401. this.peImage.Properties.NullText = "系统名称";
  402. this.peImage.Properties.ShowEditMenuItem = DevExpress.Utils.DefaultBoolean.False;
  403. this.peImage.Properties.ShowMenu = false;
  404. this.peImage.Size = new System.Drawing.Size(448, 185);
  405. this.peImage.TabIndex = 9;
  406. //
  407. // tablePanel1
  408. //
  409. this.tablePanel1.Appearance.BackColor = System.Drawing.Color.Transparent;
  410. this.tablePanel1.Appearance.Options.UseBackColor = true;
  411. this.tablePanel1.Columns.AddRange(new DevExpress.Utils.Layout.TablePanelColumn[] {
  412. new DevExpress.Utils.Layout.TablePanelColumn(DevExpress.Utils.Layout.TablePanelEntityStyle.Relative, 1F),
  413. new DevExpress.Utils.Layout.TablePanelColumn(DevExpress.Utils.Layout.TablePanelEntityStyle.AutoSize, 0F),
  414. new DevExpress.Utils.Layout.TablePanelColumn(DevExpress.Utils.Layout.TablePanelEntityStyle.Relative, 1F)});
  415. this.tablePanel1.Controls.Add(this.labelCopyright);
  416. this.tablePanel1.Dock = System.Windows.Forms.DockStyle.Bottom;
  417. this.tablePanel1.Location = new System.Drawing.Point(1, 250);
  418. this.tablePanel1.Name = "tablePanel1";
  419. this.tablePanel1.Padding = new System.Windows.Forms.Padding(1);
  420. this.tablePanel1.Rows.AddRange(new DevExpress.Utils.Layout.TablePanelRow[] {
  421. new DevExpress.Utils.Layout.TablePanelRow(DevExpress.Utils.Layout.TablePanelEntityStyle.Relative, 1F)});
  422. this.tablePanel1.Size = new System.Drawing.Size(448, 37);
  423. this.tablePanel1.TabIndex = 10;
  424. this.tablePanel1.UseSkinIndents = true;
  425. //
  426. // SplashScreen1
  427. //
  428. this.AutoScaleDimensions = new System.Drawing.SizeF(6F, 12F);
  429. this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
  430. this.ClientSize = new System.Drawing.Size(450, 288);
  431. this.Controls.Add(this.tablePanel1);
  432. this.Controls.Add(this.peImage);
  433. this.Controls.Add(this.labMsg);
  434. this.Controls.Add(this.progressBarControl);
  435. this.Name = "SplashScreen1";
  436. this.Padding = new System.Windows.Forms.Padding(1);
  437. this.Text = "SplashScreen1";
  438. ((System.ComponentModel.ISupportInitialize)(this.progressBarControl.Properties)).EndInit();
  439. ((System.ComponentModel.ISupportInitialize)(this.peImage.Properties)).EndInit();
  440. ((System.ComponentModel.ISupportInitialize)(this.tablePanel1)).EndInit();
  441. this.tablePanel1.ResumeLayout(false);
  442. this.tablePanel1.PerformLayout();
  443. this.ResumeLayout(false);
  444. this.PerformLayout();
  445. }
  446. #endregion
  447. private DevExpress.XtraEditors.MarqueeProgressBarControl progressBarControl;
  448. private DevExpress.XtraEditors.LabelControl labelCopyright;
  449. private DevExpress.XtraEditors.LabelControl labMsg;
  450. private DevExpress.XtraEditors.PictureEdit peImage;
  451. private DevExpress.Utils.Layout.TablePanel tablePanel1;
  452. }
  453. #endregion
  454. }
  455. }