private static async IAsyncEnumerable <int> CoroutineA( [EnumeratorCancellation] CancellationToken token) { var inputIdler = new InputIdler(); for (int i = 0; i < 80; i++) { // yield to the event loop to process any keyboard/mouse input first await inputIdler.Yield(token); // now we could use Task.Run for this // but let's pretend this code must execute on the UI thread Console.SetCursorPosition(0, 0); Console.Write($"{nameof(CoroutineA)}: {new String('A', i)}"); yield return(i); } }
private static async IAsyncEnumerable <int> CoroutineB( [EnumeratorCancellation] CancellationToken token) { var inputIdler = new InputIdler(); for (int i = 0; i < 80; i++) { // yield to the event loop to process any keyboard/mouse input first await inputIdler.Yield(token); Console.SetCursorPosition(0, 1); Console.Write($"{nameof(CoroutineB)}: {new String('B', i)}"); // slow down CoroutineB await Task.Delay(25, token); yield return(i); } }
private Form CreateUI() { var form = new Form { Text = Application.ProductName, Width = 800, Height = 400, StartPosition = FormStartPosition.CenterScreen }; var textBox = new TextBox { Multiline = true, AcceptsReturn = true, Dock = DockStyle.Fill }; form.Controls.Add(textBox); var menu = new MenuStrip { Dock = DockStyle.Top }; var actionMenu = new ToolStripMenuItem("Coroutines"); menu.Items.Add(actionMenu); var actionItems = actionMenu.DropDownItems; actionItems.Add( "IEnumerable/Pull-based coroutines", null, StartCoroutineDemo); actionItems.Add( "IAsyncEnumerable/Push-based coroutines", null, StartAsyncCoroutineDemo); actionItems.Add( "IAsyncEnumerable/Push-based mutual coroutines", null, StartAsyncCoroutineDemoMutual); menu.Items.Add( "Stop", null, (s, e) => Stop()); menu.Items.Add( "Close", null, (s, e) => form.Close()); CancellationTokenSource?uiWorkCts = null; menu.Items.Add( "Show TickCount", null, async(s, e) => { // not good: do some silly work on the UI thread in a hot loop uiWorkCts?.Cancel(); uiWorkCts = CancellationTokenSource.CreateLinkedTokenSource(Token); uiWorkCts.CancelAfter(5000); var idler = new InputIdler(); while (!uiWorkCts.Token.IsCancellationRequested) { textBox.Text = $"TickCount: {Environment.TickCount}"; form.Refresh(); if (InputIdler.AnyInputMessage()) { // process messages await idler.Yield(CancellationToken.None); } } textBox.Text = String.Empty; }); form.MainMenuStrip = menu; form.Controls.Add(menu); form.FormClosing += (s, e) => Stop(); return(form); }