Threading.cs 8.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246
  1. using System;
  2. using System.Collections.ObjectModel;
  3. using System.Threading;
  4. using System.Threading.Tasks;
  5. using Terminal.Gui;
  6. namespace UICatalog.Scenarios;
  7. [ScenarioMetadata ("Threading", "Demonstration of how to use threading in different ways")]
  8. [ScenarioCategory ("Threading")]
  9. public class Threading : Scenario
  10. {
  11. private readonly ObservableCollection<string> _log = [];
  12. private Action _action;
  13. private Button _btnActionCancel;
  14. private CancellationTokenSource _cancellationTokenSource;
  15. private EventHandler _handler;
  16. private ListView _itemsList;
  17. private Action _lambda;
  18. private ListView _logJob;
  19. private Action _sync;
  20. public override void Main ()
  21. {
  22. Application.Init ();
  23. var win = new Window { Title = GetQuitKeyAndName () };
  24. _action = LoadData;
  25. _lambda = async () =>
  26. {
  27. _itemsList.Source = null;
  28. LogJob ("Loading task lambda");
  29. ObservableCollection<string> items = await LoadDataAsync ();
  30. LogJob ("Returning from task lambda");
  31. await _itemsList.SetSourceAsync (items);
  32. };
  33. _handler = async (s, e) =>
  34. {
  35. _itemsList.Source = null;
  36. LogJob ("Loading task handler");
  37. ObservableCollection<string> items = await LoadDataAsync ();
  38. LogJob ("Returning from task handler");
  39. await _itemsList.SetSourceAsync (items);
  40. };
  41. _sync = () =>
  42. {
  43. _itemsList.Source = null;
  44. LogJob ("Loading task synchronous");
  45. ObservableCollection<string> items =
  46. ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"];
  47. LogJob ("Returning from task synchronous");
  48. _itemsList.SetSource (items);
  49. };
  50. _btnActionCancel = new Button { X = 1, Y = 1, Text = "Cancelable Load Items" };
  51. _btnActionCancel.Accepting += (s, e) => Application.Invoke (CallLoadItemsAsync);
  52. win.Add (new Label { X = Pos.X (_btnActionCancel), Y = Pos.Y (_btnActionCancel) + 4, Text = "Data Items:" });
  53. _itemsList = new ListView
  54. {
  55. X = Pos.X (_btnActionCancel),
  56. Y = Pos.Y (_btnActionCancel) + 6,
  57. Width = 10,
  58. Height = 10,
  59. ColorScheme = Colors.ColorSchemes ["TopLevel"]
  60. };
  61. win.Add (new Label { X = Pos.Right (_itemsList) + 10, Y = Pos.Y (_btnActionCancel) + 4, Text = "Task Logs:" });
  62. _logJob = new ListView
  63. {
  64. X = Pos.Right (_itemsList) + 10,
  65. Y = Pos.Y (_itemsList),
  66. Width = 50,
  67. Height = Dim.Fill (),
  68. ColorScheme = Colors.ColorSchemes ["TopLevel"],
  69. Source = new ListWrapper<string> (_log)
  70. };
  71. var text = new TextField { X = 1, Y = 3, Width = 100, Text = "Type anything after press the button" };
  72. var btnAction = new Button { X = 80, Y = 10, Text = "Load Data Action" };
  73. btnAction.Accepting += (s, e) => _action.Invoke ();
  74. var btnLambda = new Button { X = 80, Y = 12, Text = "Load Data Lambda" };
  75. btnLambda.Accepting += (s, e) => _lambda.Invoke ();
  76. var btnHandler = new Button { X = 80, Y = 14, Text = "Load Data Handler" };
  77. btnHandler.Accepting += (s, e) => _handler.Invoke (null, EventArgs.Empty);
  78. var btnSync = new Button { X = 80, Y = 16, Text = "Load Data Synchronous" };
  79. btnSync.Accepting += (s, e) => _sync.Invoke ();
  80. var btnMethod = new Button { X = 80, Y = 18, Text = "Load Data Method" };
  81. btnMethod.Accepting += async (s, e) => await MethodAsync ();
  82. var btnClearData = new Button { X = 80, Y = 20, Text = "Clear Data" };
  83. btnClearData.Accepting += (s, e) =>
  84. {
  85. _itemsList.Source = null;
  86. LogJob ("Cleaning Data");
  87. };
  88. var btnQuit = new Button { X = 80, Y = 22, Text = "Quit" };
  89. btnQuit.Accepting += (s, e) => Application.RequestStop ();
  90. win.Add (
  91. _itemsList,
  92. _btnActionCancel,
  93. _logJob,
  94. text,
  95. btnAction,
  96. btnLambda,
  97. btnHandler,
  98. btnSync,
  99. btnMethod,
  100. btnClearData,
  101. btnQuit
  102. );
  103. void Win_Loaded (object sender, EventArgs args)
  104. {
  105. _btnActionCancel.SetFocus ();
  106. win.Loaded -= Win_Loaded;
  107. }
  108. win.Loaded += Win_Loaded;
  109. Application.Run (win);
  110. win.Dispose ();
  111. Application.Shutdown ();
  112. }
  113. private async void CallLoadItemsAsync ()
  114. {
  115. _cancellationTokenSource = new CancellationTokenSource ();
  116. _itemsList.Source = null;
  117. LogJob ("Clicked the button");
  118. if (_btnActionCancel.Text != "Cancel")
  119. {
  120. _btnActionCancel.Text = "Cancel";
  121. }
  122. else
  123. {
  124. _btnActionCancel.Text = "Cancelable Load Items";
  125. await _cancellationTokenSource.CancelAsync ();
  126. }
  127. try
  128. {
  129. if (_cancellationTokenSource.Token.IsCancellationRequested)
  130. {
  131. _cancellationTokenSource.Token.ThrowIfCancellationRequested ();
  132. }
  133. LogJob ($"Calling task Thread:{Thread.CurrentThread.ManagedThreadId} {DateTime.Now}");
  134. ObservableCollection<string> items = await Task.Run (LoadItemsAsync, _cancellationTokenSource.Token);
  135. if (!_cancellationTokenSource.IsCancellationRequested)
  136. {
  137. LogJob (
  138. $"Returned from task Thread:{Thread.CurrentThread.ManagedThreadId} {DateTime.Now}"
  139. );
  140. await _itemsList.SetSourceAsync (items);
  141. LogJob (
  142. $"Finished populate list view Thread:{Thread.CurrentThread.ManagedThreadId} {DateTime.Now}"
  143. );
  144. _btnActionCancel.Text = "Cancelable Load Items";
  145. }
  146. else
  147. {
  148. LogJob ("Task was canceled!");
  149. }
  150. }
  151. catch (OperationCanceledException ex)
  152. {
  153. LogJob (ex.Message);
  154. }
  155. }
  156. private async void LoadData ()
  157. {
  158. _itemsList.Source = null;
  159. LogJob ("Loading task");
  160. ObservableCollection<string> items = await LoadDataAsync ();
  161. LogJob ("Returning from task");
  162. await _itemsList.SetSourceAsync (items);
  163. }
  164. private async Task<ObservableCollection<string>> LoadDataAsync ()
  165. {
  166. _itemsList.Source = null;
  167. LogJob ("Starting delay");
  168. await Task.Delay (3000);
  169. LogJob ("Finished delay");
  170. return
  171. [
  172. "One",
  173. "Two",
  174. "Three",
  175. "Four",
  176. "Five",
  177. "Six",
  178. "Seven",
  179. "Eight",
  180. "Nine",
  181. "Ten",
  182. "Four",
  183. "Five",
  184. "Six",
  185. "Seven",
  186. "Eight",
  187. "Nine",
  188. "Ten"
  189. ];
  190. }
  191. private async Task<ObservableCollection<string>> LoadItemsAsync ()
  192. {
  193. // Do something that takes lot of times.
  194. LogJob ($"Starting delay Thread:{Thread.CurrentThread.ManagedThreadId} {DateTime.Now}");
  195. await Task.Delay (5000);
  196. LogJob ($"Finished delay Thread:{Thread.CurrentThread.ManagedThreadId} {DateTime.Now}");
  197. return ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"];
  198. }
  199. private void LogJob (string job)
  200. {
  201. _log.Add (job);
  202. _logJob.MoveDown ();
  203. }
  204. private async Task MethodAsync ()
  205. {
  206. _itemsList.Source = null;
  207. LogJob ("Loading task method");
  208. ObservableCollection<string> items = ["One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten"];
  209. await Task.Delay (3000);
  210. LogJob ("Returning from task method");
  211. await _itemsList.SetSourceAsync (items);
  212. _itemsList.SetNeedsDraw ();
  213. }
  214. }