diff --git a/UICatalog/Scenarios/Threading.cs b/UICatalog/Scenarios/Threading.cs new file mode 100644 index 000000000..28b2a72d7 --- /dev/null +++ b/UICatalog/Scenarios/Threading.cs @@ -0,0 +1,162 @@ +using System; +using System.Collections.Generic; +using System.Threading; +using System.Threading.Tasks; +using Terminal.Gui; + +namespace UICatalog { + [ScenarioMetadata (Name: "Threading", Description: "Demonstration of how to use threading in different ways")] + [ScenarioCategory ("Threading")] + class Threading : Scenario { + private Action _action; + private Action _lambda; + private EventHandler _handler; + private Action _sync; + + private ListView _itemsList; + private Button _btnActionCancel; + List log = new List (); + private ListView _logJob; + + public override void Setup () + { + _action = LoadData; + _lambda = async () => { + _itemsList.Source = null; + LogJob ("Loading task lambda"); + var items = await LoadDataAsync (); + LogJob ("Returning from task lambda"); + _itemsList.SetSource (items); + }; + _handler = async (s, e) => { + _itemsList.Source = null; + LogJob ("Loading task handler"); + var items = await LoadDataAsync (); + LogJob ("Returning from task handler"); + _itemsList.SetSource (items); + + }; + _sync = () => { + _itemsList.Source = null; + LogJob ("Loading task synchronous"); + List items = new List () { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten" }; + LogJob ("Returning from task synchronous"); + _itemsList.SetSource (items); + }; + + Application.Init (); + + _btnActionCancel = new Button (1, 1, "Cancelable Load Items"); + _btnActionCancel.Clicked += () => Application.MainLoop.Invoke (CallLoadItemsAsync); + + _itemsList = new ListView { + X = Pos.X (_btnActionCancel), + Y = Pos.Y (_btnActionCancel) + 4, + Width = 10, + Height = 10 + }; + + _logJob = new ListView (log) { + X = Pos.Right (_itemsList) + 10, + Y = Pos.Y (_itemsList), + Width = 50, + Height = Dim.Fill () + }; + + var text = new TextField (1, 3, 100, "Type anything after press the button"); + + var _btnAction = new Button (80, 10, "Load Data Action"); + _btnAction.Clicked += () => _action.Invoke (); + var _btnLambda = new Button (80, 12, "Load Data Lambda"); + _btnLambda.Clicked += () => _lambda.Invoke (); + var _btnHandler = new Button (80, 14, "Load Data Handler"); + _btnHandler.Clicked += () => _handler.Invoke (null, new EventArgs ()); + var _btnSync = new Button (80, 16, "Load Data Synchronous"); + _btnSync.Clicked += () => _sync.Invoke (); + var _btnMethod = new Button (80, 18, "Load Data Method"); + _btnMethod.Clicked += async () => await MethodAsync (); + var _btnClearData = new Button (80, 20, "Clear Data"); + _btnClearData.Clicked += () => { _itemsList.Source = null; LogJob ("Cleaning Data"); }; + var _btnQuit = new Button (80, 22, "Quit"); + _btnQuit.Clicked += Application.RequestStop; + + Win.Add (_itemsList, _btnActionCancel, _logJob, text, _btnAction, _btnLambda, _btnHandler, _btnSync, _btnMethod, _btnClearData, _btnQuit); + Application.Top.Add (Win); + Application.Run (); + + } + + private async void LoadData () + { + _itemsList.Source = null; + LogJob ("Loading task"); + var items = await LoadDataAsync (); + LogJob ("Returning from task"); + _itemsList.SetSource (items); + } + + private void LogJob (string job) + { + log.Add (job); + _logJob.MoveDown (); + } + + private async Task> LoadDataAsync () + { + _itemsList.Source = null; + LogJob ("Starting delay"); + await Task.Delay (3000); + LogJob ("Finished delay"); + return new List () { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten" }; + } + + private async Task MethodAsync () + { + _itemsList.Source = null; + LogJob ("Loading task method"); + List items = new List () { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten" }; + await Task.Delay (3000); + LogJob ("Returning from task method"); + await _itemsList.SetSourceAsync (items); + } + + private CancellationTokenSource cancellationTokenSource; + + private async void CallLoadItemsAsync () + { + cancellationTokenSource = new CancellationTokenSource (); + _itemsList.Source = null; + LogJob ($"Clicked the button"); + if (_btnActionCancel.Text == "Cancel") { + _btnActionCancel.Text = "Cancelable Load Items"; + cancellationTokenSource.Cancel (); + } else + _btnActionCancel.Text = "Cancel"; + try { + if (cancellationTokenSource.Token.IsCancellationRequested) + cancellationTokenSource.Token.ThrowIfCancellationRequested (); + LogJob ($"Calling task Thread:{Thread.CurrentThread.ManagedThreadId} {DateTime.Now}"); + var items = await Task.Run (LoadItemsAsync, cancellationTokenSource.Token); + if (!cancellationTokenSource.IsCancellationRequested) { + LogJob ($"Returned from task Thread:{Thread.CurrentThread.ManagedThreadId} {DateTime.Now}"); + _itemsList.SetSource (items); + LogJob ($"Finished populate list view Thread:{Thread.CurrentThread.ManagedThreadId} {DateTime.Now}"); + _btnActionCancel.Text = "Load Items"; + } else { + LogJob ("Task was canceled!"); + } + } catch (OperationCanceledException ex) { + LogJob (ex.Message); + } + } + + private async Task> LoadItemsAsync () + { + // Do something that takes lot of times. + LogJob ($"Starting delay Thread:{Thread.CurrentThread.ManagedThreadId} {DateTime.Now}"); + await Task.Delay (5000); + LogJob ($"Finished delay Thread:{Thread.CurrentThread.ManagedThreadId} {DateTime.Now}"); + return new List () { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten" }; + } + } +}