SingleBackgroundWorker.cs 4.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Threading;
  5. using Terminal.Gui;
  6. namespace UICatalog.Scenarios {
  7. [ScenarioMetadata (Name: "Single BackgroundWorker", Description: "A single BackgroundWorker threading opening another Toplevel")]
  8. [ScenarioCategory ("Threading")]
  9. [ScenarioCategory ("Top Level Windows")]
  10. public class SingleBackgroundWorker : Scenario {
  11. public override void Run ()
  12. {
  13. Application.Top.Dispose ();
  14. Application.Run<MainApp> ();
  15. Application.Top.Dispose ();
  16. }
  17. public class MainApp : Toplevel {
  18. private BackgroundWorker worker;
  19. private List<string> log = new List<string> ();
  20. private DateTime? startStaging;
  21. private ListView listLog;
  22. public MainApp ()
  23. {
  24. var menu = new MenuBar (new MenuBarItem [] {
  25. new MenuBarItem ("_Options", new MenuItem [] {
  26. new MenuItem ("_Run Worker", "", () => RunWorker(), null, null, Key.CtrlMask | Key.R),
  27. null,
  28. new MenuItem ("_Quit", "", () => Application.RequestStop(), null, null, Key.CtrlMask | Key.Q)
  29. })
  30. });
  31. Add (menu);
  32. var statusBar = new StatusBar (new [] {
  33. new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Exit", () => Application.RequestStop()),
  34. new StatusItem(Key.CtrlMask | Key.P, "~^R~ Run Worker", () => RunWorker())
  35. });
  36. Add (statusBar);
  37. var top = new Toplevel ();
  38. top.Add (new Label ("Worker Log") {
  39. X = Pos.Center (),
  40. Y = 0
  41. });
  42. listLog = new ListView (log) {
  43. X = 0,
  44. Y = 2,
  45. Width = Dim.Fill (),
  46. Height = Dim.Fill ()
  47. };
  48. top.Add (listLog);
  49. Add (top);
  50. }
  51. private void RunWorker ()
  52. {
  53. worker = new BackgroundWorker () { WorkerSupportsCancellation = true };
  54. var cancel = new Button ("Cancel Worker");
  55. cancel.Clicked += (s,e) => {
  56. if (worker == null) {
  57. log.Add ($"Worker is not running at {DateTime.Now}!");
  58. listLog.SetNeedsDisplay ();
  59. return;
  60. }
  61. log.Add ($"Worker {startStaging}.{startStaging:fff} is canceling at {DateTime.Now}!");
  62. listLog.SetNeedsDisplay ();
  63. worker.CancelAsync ();
  64. };
  65. startStaging = DateTime.Now;
  66. log.Add ($"Worker is started at {startStaging}.{startStaging:fff}");
  67. listLog.SetNeedsDisplay ();
  68. var md = new Dialog ($"Running Worker started at {startStaging}.{startStaging:fff}", cancel);
  69. md.Add (new Label ("Wait for worker to finish...") {
  70. X = Pos.Center (),
  71. Y = Pos.Center ()
  72. });
  73. worker.DoWork += (s, e) => {
  74. var stageResult = new List<string> ();
  75. for (int i = 0; i < 500; i++) {
  76. stageResult.Add ($"Worker {i} started at {DateTime.Now}");
  77. e.Result = stageResult;
  78. Thread.Sleep (1);
  79. if (worker.CancellationPending) {
  80. e.Cancel = true;
  81. return;
  82. }
  83. }
  84. };
  85. worker.RunWorkerCompleted += (s, e) => {
  86. if (md.IsCurrentTop) {
  87. //Close the dialog
  88. Application.RequestStop ();
  89. }
  90. if (e.Error != null) {
  91. // Failed
  92. log.Add ($"Exception occurred {e.Error.Message} on Worker {startStaging}.{startStaging:fff} at {DateTime.Now}");
  93. listLog.SetNeedsDisplay ();
  94. } else if (e.Cancelled) {
  95. // Canceled
  96. log.Add ($"Worker {startStaging}.{startStaging:fff} was canceled at {DateTime.Now}!");
  97. listLog.SetNeedsDisplay ();
  98. } else {
  99. // Passed
  100. log.Add ($"Worker {startStaging}.{startStaging:fff} was completed at {DateTime.Now}.");
  101. listLog.SetNeedsDisplay ();
  102. Application.Refresh ();
  103. var builderUI = new StagingUIController (startStaging, e.Result as List<string>);
  104. builderUI.Load ();
  105. }
  106. worker = null;
  107. };
  108. worker.RunWorkerAsync ();
  109. Application.Run (md);
  110. }
  111. }
  112. public class StagingUIController : Window {
  113. Toplevel top;
  114. public StagingUIController (DateTime? start, List<string> list)
  115. {
  116. top = new Toplevel (Application.Top.Frame);
  117. top.KeyPress += (s,e) => {
  118. // Prevents Ctrl+Q from closing this.
  119. // Only Ctrl+C is allowed.
  120. if (e.KeyEvent.Key == (Key.Q | Key.CtrlMask)) {
  121. e.Handled = true;
  122. }
  123. };
  124. bool Close ()
  125. {
  126. var n = MessageBox.Query (50, 7, "Close Window.", "Are you sure you want to close this window?", "Yes", "No");
  127. return n == 0;
  128. }
  129. var menu = new MenuBar (new MenuBarItem [] {
  130. new MenuBarItem ("_Stage", new MenuItem [] {
  131. new MenuItem ("_Close", "", () => { if (Close()) { Application.RequestStop(); } }, null, null, Key.CtrlMask | Key.C)
  132. })
  133. });
  134. top.Add (menu);
  135. var statusBar = new StatusBar (new [] {
  136. new StatusItem(Key.CtrlMask | Key.C, "~^C~ Close", () => { if (Close()) { Application.RequestStop(); } }),
  137. });
  138. top.Add (statusBar);
  139. Title = $"Worker started at {start}.{start:fff}";
  140. ColorScheme = Colors.Base;
  141. Add (new ListView (list) {
  142. X = 0,
  143. Y = 0,
  144. Width = Dim.Fill (),
  145. Height = Dim.Fill ()
  146. });
  147. top.Add (this);
  148. }
  149. public void Load ()
  150. {
  151. Application.Run (top);
  152. }
  153. }
  154. }
  155. }