Files
Terminal.Gui/UICatalog/Scenarios/BackgroundWorkerSample.cs

209 lines
5.6 KiB
C#

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Threading;
using Terminal.Gui;
namespace UICatalog {
[ScenarioMetadata (Name: "BackgroundWorker", Description: "A persisting multi Toplevel BackgroundWorker threading")]
[ScenarioCategory ("Threading")]
[ScenarioCategory ("TopLevel")]
[ScenarioCategory ("Dialogs")]
[ScenarioCategory ("Controls")]
class BackgroundWorkerSample : Scenario {
public override void Run ()
{
Top.Dispose ();
Application.Run<MainApp> ();
Top.Dispose ();
}
}
public class MainApp : Toplevel {
private List<string> log = new List<string> ();
private ListView listLog;
private Dictionary<StagingUIController, BackgroundWorker> stagingWorkers;
public MainApp ()
{
var menu = new MenuBar (new MenuBarItem [] {
new MenuBarItem ("_Options", new MenuItem [] {
new MenuItem ("_Run Worker", "", () => RunWorker(), null, null, Key.CtrlMask | Key.R),
new MenuItem ("_Cancel Worker", "", () => CancelWorker(), null, null, Key.CtrlMask | Key.C),
null,
new MenuItem ("_Quit", "", () => Application.RequestStop (), null, null, Key.CtrlMask | Key.Q)
})
});
Add (menu);
var statusBar = new StatusBar (new [] {
new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Exit", () => Application.RequestStop()),
new StatusItem(Key.CtrlMask | Key.P, "~^R~ Run Worker", () => RunWorker()),
new StatusItem(Key.CtrlMask | Key.P, "~^C~ Cancel Worker", () => CancelWorker())
});
Add (statusBar);
var top = new Toplevel ();
top.Add (new Label ("Worker Log") {
X = Pos.Center (),
Y = 0
});
listLog = new ListView (log) {
X = 0,
Y = 2,
Width = Dim.Fill (),
Height = Dim.Fill ()
};
top.Add (listLog);
Add (top);
}
private void RunWorker ()
{
var stagingUI = new StagingUIController ();
var worker = new BackgroundWorker () { WorkerSupportsCancellation = true };
worker.DoWork += (s, e) => {
var stageResult = new List<string> ();
for (int i = 0; i < 500; i++) {
stageResult.Add (
$"Worker {i} started at {DateTime.UtcNow}");
e.Result = stageResult;
Thread.Sleep (1);
if (worker.CancellationPending) {
e.Cancel = true;
return;
}
}
};
worker.RunWorkerCompleted += (s, e) => {
if (e.Error != null) {
// Failed
log.Add ($"Exception occurred {e.Error.Message} on Worker {stagingUI.StartStaging}.{stagingUI.StartStaging:fff} at {DateTime.UtcNow}");
listLog.SetNeedsDisplay ();
} else if (e.Cancelled) {
// Canceled
log.Add ($"Worker {stagingUI.StartStaging}.{stagingUI.StartStaging:fff} was canceled at {DateTime.UtcNow}!");
listLog.SetNeedsDisplay ();
} else {
// Passed
log.Add ($"Worker {stagingUI.StartStaging}.{stagingUI.StartStaging:fff} was completed at {DateTime.UtcNow}.");
listLog.SetNeedsDisplay ();
Application.Refresh ();
stagingUI.Load (e.Result as List<string>);
}
stagingWorkers.Remove (stagingUI);
};
Application.Run (stagingUI);
if (stagingUI.StartStaging != null) {
log.Add ($"Worker is started at {stagingUI.StartStaging}.{stagingUI.StartStaging:fff}");
listLog.SetNeedsDisplay ();
if (stagingWorkers == null) {
stagingWorkers = new Dictionary<StagingUIController, BackgroundWorker> ();
}
stagingWorkers.Add (stagingUI, worker);
worker.RunWorkerAsync ();
}
}
private void CancelWorker ()
{
if (stagingWorkers.Count == 0) {
log.Add ($"Worker is not running at {DateTime.UtcNow}!");
listLog.SetNeedsDisplay ();
return;
}
var eStaging = stagingWorkers.GetEnumerator ();
eStaging.MoveNext ();
var fStaging = eStaging.Current;
var stagingUI = fStaging.Key;
var worker = fStaging.Value;
worker.CancelAsync ();
log.Add ($"Worker {stagingUI.StartStaging}.{stagingUI.StartStaging:fff} is canceling at {DateTime.UtcNow}!");
listLog.SetNeedsDisplay ();
}
}
public class StagingUIController : Window {
private Label label;
private ListView listView;
private Button start;
private Button close;
public DateTime? StartStaging { get; private set; }
public StagingUIController ()
{
X = Pos.Center ();
Y = Pos.Center ();
Width = Dim.Percent (85);
Height = Dim.Percent (85);
ColorScheme = Colors.Dialog;
Modal = true;
Title = "Run Worker";
label = new Label ("Press start to do the work or close to exit.") {
X = Pos.Center (),
Y = 1,
ColorScheme = Colors.Dialog
};
Add (label);
listView = new ListView () {
X = 0,
Y = 2,
Width = Dim.Fill (),
Height = Dim.Fill (2)
};
Add (listView);
start = new Button ("Start") { IsDefault = true };
start.Clicked += () => {
StartStaging = DateTime.UtcNow;
Application.RequestStop ();
};
Add (start);
close = new Button ("Close");
close.Clicked += () => Application.RequestStop ();
Add (close);
LayoutStarted += (_) => {
var btnsWidth = start.Bounds.Width + close.Bounds.Width + 2 - 1;
var shiftLeft = Math.Max ((Bounds.Width - btnsWidth) / 2 - 2, 0);
shiftLeft += close.Bounds.Width + 1;
close.X = Pos.AnchorEnd (shiftLeft);
close.Y = Pos.AnchorEnd (1);
shiftLeft += start.Bounds.Width + 1;
start.X = Pos.AnchorEnd (shiftLeft);
start.Y = Pos.AnchorEnd (1);
};
}
public void Load (List<string> list)
{
var stagingUI = new StagingUIController ();
stagingUI.Title = $"Worker started at {StartStaging}.{StartStaging:fff}";
stagingUI.label.Text = "Work list:";
stagingUI.listView.SetSource (list);
stagingUI.start.Visible = false;
Application.Run (stagingUI);
}
}
}