SingleBackgroundWorker.cs 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. using System;
  2. using System.Collections.Generic;
  3. using System.Collections.ObjectModel;
  4. using System.ComponentModel;
  5. using System.Threading;
  6. namespace UICatalog.Scenarios;
  7. [ScenarioMetadata ("Single BackgroundWorker", "A single BackgroundWorker threading opening another Toplevel")]
  8. [ScenarioCategory ("Threading")]
  9. [ScenarioCategory ("Arrangement")]
  10. [ScenarioCategory ("Runnable")]
  11. public class SingleBackgroundWorker : Scenario
  12. {
  13. public override void Main ()
  14. {
  15. Application.Run<MainApp> ().Dispose ();
  16. Application.Shutdown ();
  17. }
  18. public class MainApp : Toplevel
  19. {
  20. private readonly ListView _listLog;
  21. private readonly ObservableCollection<string> _log = [];
  22. private DateTime? _startStaging;
  23. private BackgroundWorker _worker;
  24. public MainApp ()
  25. {
  26. var menu = new MenuBar
  27. {
  28. Menus =
  29. [
  30. new (
  31. "_Options",
  32. new MenuItem []
  33. {
  34. new (
  35. "_Run Worker",
  36. "",
  37. () => RunWorker (),
  38. null,
  39. null,
  40. KeyCode.CtrlMask | KeyCode.R
  41. ),
  42. null,
  43. new (
  44. "_Quit",
  45. "",
  46. () => Application.RequestStop (),
  47. null,
  48. null,
  49. Application.QuitKey
  50. )
  51. }
  52. )
  53. ]
  54. };
  55. var statusBar = new StatusBar (
  56. [
  57. new (Application.QuitKey, "Quit", () => Application.RequestStop ()),
  58. new (Key.R.WithCtrl, "Run Worker", RunWorker)
  59. ]);
  60. var workerLogTop = new Toplevel
  61. {
  62. Title = "Worker Log Top"
  63. };
  64. workerLogTop.Add (
  65. new Label { X = Pos.Center (), Y = 0, Text = "Worker Log" }
  66. );
  67. _listLog = new ()
  68. {
  69. X = 0,
  70. Y = 2,
  71. Width = Dim.Fill (),
  72. Height = Dim.Fill (),
  73. Source = new ListWrapper<string> (_log)
  74. };
  75. workerLogTop.Add (_listLog);
  76. workerLogTop.Y = 1;
  77. workerLogTop.Height = Dim.Fill (Dim.Func (() => statusBar.Frame.Height));
  78. Add (menu, workerLogTop, statusBar);
  79. Title = "MainApp";
  80. }
  81. private void RunWorker ()
  82. {
  83. _worker = new () { WorkerSupportsCancellation = true };
  84. var cancel = new Button { Text = "Cancel Worker" };
  85. cancel.Accepting += (s, e) =>
  86. {
  87. if (_worker == null)
  88. {
  89. _log.Add ($"Worker is not running at {DateTime.Now}!");
  90. _listLog.SetNeedsDraw ();
  91. return;
  92. }
  93. _log.Add (
  94. $"Worker {_startStaging}.{_startStaging:fff} is canceling at {DateTime.Now}!"
  95. );
  96. _listLog.SetNeedsDraw ();
  97. _worker.CancelAsync ();
  98. };
  99. _startStaging = DateTime.Now;
  100. _log.Add ($"Worker is started at {_startStaging}.{_startStaging:fff}");
  101. _listLog.SetNeedsDraw ();
  102. var md = new Dialog
  103. {
  104. Title = $"Running Worker started at {_startStaging}.{_startStaging:fff}", Buttons = [cancel]
  105. };
  106. md.Add (
  107. new Label { X = Pos.Center (), Y = Pos.Center (), Text = "Wait for worker to finish..." }
  108. );
  109. _worker.DoWork += (s, e) =>
  110. {
  111. List<string> stageResult = new ();
  112. for (var i = 0; i < 200; i++)
  113. {
  114. stageResult.Add ($"Worker {i} started at {DateTime.Now}");
  115. e.Result = stageResult;
  116. Thread.Sleep (1);
  117. if (_worker.CancellationPending)
  118. {
  119. e.Cancel = true;
  120. return;
  121. }
  122. }
  123. };
  124. _worker.RunWorkerCompleted += (s, e) =>
  125. {
  126. if (md.IsCurrentTop)
  127. {
  128. //Close the dialog
  129. Application.RequestStop ();
  130. }
  131. if (e.Error != null)
  132. {
  133. // Failed
  134. _log.Add (
  135. $"Exception occurred {e.Error.Message} on Worker {_startStaging}.{_startStaging:fff} at {DateTime.Now}"
  136. );
  137. _listLog.SetNeedsDraw ();
  138. }
  139. else if (e.Cancelled)
  140. {
  141. // Canceled
  142. _log.Add (
  143. $"Worker {_startStaging}.{_startStaging:fff} was canceled at {DateTime.Now}!"
  144. );
  145. _listLog.SetNeedsDraw ();
  146. }
  147. else
  148. {
  149. // Passed
  150. _log.Add (
  151. $"Worker {_startStaging}.{_startStaging:fff} was completed at {DateTime.Now}."
  152. );
  153. _listLog.SetNeedsDraw ();
  154. Application.LayoutAndDraw ();
  155. var builderUI =
  156. new StagingUIController (_startStaging, e.Result as ObservableCollection<string>);
  157. Toplevel top = Application.Top;
  158. top.Visible = false;
  159. Application.Top.Visible = false;
  160. builderUI.Load ();
  161. builderUI.Dispose ();
  162. top.Visible = true;
  163. }
  164. _worker = null;
  165. };
  166. _worker.RunWorkerAsync ();
  167. Application.Run (md);
  168. md.Dispose ();
  169. }
  170. }
  171. public class StagingUIController : Window
  172. {
  173. private Toplevel _top;
  174. public StagingUIController (DateTime? start, ObservableCollection<string> list)
  175. {
  176. _top = new ()
  177. {
  178. Title = "_top", Width = Dim.Fill (), Height = Dim.Fill (), Modal = true
  179. };
  180. _top.KeyDown += (s, e) =>
  181. {
  182. // Prevents App.QuitKey from closing this.
  183. // Only Ctrl+C is allowed.
  184. if (e == Application.QuitKey)
  185. {
  186. e.Handled = true;
  187. }
  188. };
  189. bool Close ()
  190. {
  191. int n = MessageBox.Query (
  192. 50,
  193. 7,
  194. "Close Window.",
  195. "Are you sure you want to close this window?",
  196. "Yes",
  197. "No"
  198. );
  199. return n == 0;
  200. }
  201. var menu = new MenuBar
  202. {
  203. Menus =
  204. [
  205. new (
  206. "_Stage",
  207. new MenuItem []
  208. {
  209. new (
  210. "_Close",
  211. "",
  212. () =>
  213. {
  214. if (Close ())
  215. {
  216. Application.RequestStop ();
  217. }
  218. },
  219. null,
  220. null,
  221. KeyCode.CtrlMask | KeyCode.C
  222. )
  223. }
  224. )
  225. ]
  226. };
  227. _top.Add (menu);
  228. var statusBar = new StatusBar (
  229. [
  230. new (
  231. Key.C.WithCtrl,
  232. "Close",
  233. () =>
  234. {
  235. if (Close ())
  236. {
  237. Application.RequestStop ();
  238. }
  239. }
  240. )
  241. ]);
  242. _top.Add (statusBar);
  243. Y = 1;
  244. Height = Dim.Fill (1);
  245. Title = $"Worker started at {start}.{start:fff}";
  246. SchemeName = "Base";
  247. Add (
  248. new ListView
  249. {
  250. X = 0,
  251. Y = 0,
  252. Width = Dim.Fill (),
  253. Height = Dim.Fill (),
  254. Source = new ListWrapper<string> (list)
  255. }
  256. );
  257. _top.Add (this);
  258. }
  259. public void Load ()
  260. {
  261. Application.Run (_top);
  262. _top.Dispose ();
  263. _top = null;
  264. }
  265. }
  266. }