123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386 |
- using System;
- using System.Collections.Generic;
- using System.ComponentModel;
- using System.Threading;
- using System.Threading.Tasks;
- using Terminal.Gui;
- namespace UICatalog.Scenarios {
- [ScenarioMetadata (Name: "BackgroundWorker Collection", Description: "A persisting multi Toplevel BackgroundWorker threading")]
- [ScenarioCategory ("Threading")]
- [ScenarioCategory ("Top Level Windows")]
- [ScenarioCategory ("Dialogs")]
- [ScenarioCategory ("Controls")]
- public class BackgroundWorkerCollection : Scenario {
- public override void Run ()
- {
- Application.Run<MdiMain> ();
- }
- class MdiMain : Toplevel {
- private WorkerApp workerApp;
- private bool canOpenWorkerApp;
- MenuBar menu;
- public MdiMain ()
- {
- Data = "MdiMain";
- IsMdiContainer = true;
- workerApp = new WorkerApp () { Visible = false };
- menu = new MenuBar (new MenuBarItem [] {
- new MenuBarItem ("_Options", new MenuItem [] {
- new MenuItem ("_Run Worker", "", () => workerApp.RunWorker(), null, null, Key.CtrlMask | Key.R),
- new MenuItem ("_Cancel Worker", "", () => workerApp.CancelWorker(), null, null, Key.CtrlMask | Key.C),
- null,
- new MenuItem ("_Quit", "", () => Quit(), null, null, Key.CtrlMask | Key.Q)
- }),
- new MenuBarItem ("_View", new MenuItem [] { }),
- new MenuBarItem ("_Window", new MenuItem [] { })
- });
- menu.MenuOpening += Menu_MenuOpening;
- Add (menu);
- var statusBar = new StatusBar (new [] {
- new StatusItem(Key.CtrlMask | Key.Q, "~^Q~ Exit", () => Quit()),
- new StatusItem(Key.CtrlMask | Key.R, "~^R~ Run Worker", () => workerApp.RunWorker()),
- new StatusItem(Key.CtrlMask | Key.C, "~^C~ Cancel Worker", () => workerApp.CancelWorker())
- });
- Add (statusBar);
- Activate += MdiMain_Activate;
- Deactivate += MdiMain_Deactivate;
- Closed += MdiMain_Closed;
- Application.Iteration += () => {
- if (canOpenWorkerApp && !workerApp.Running && Application.MdiTop.Running) {
- Application.Run (workerApp);
- }
- };
- }
- private void MdiMain_Closed (Toplevel obj)
- {
- workerApp.Dispose ();
- Dispose ();
- }
- private void Menu_MenuOpening (MenuOpeningEventArgs menu)
- {
- if (!canOpenWorkerApp) {
- canOpenWorkerApp = true;
- return;
- }
- if (menu.CurrentMenu.Title == "_Window") {
- menu.NewMenuBarItem = OpenedWindows ();
- } else if (menu.CurrentMenu.Title == "_View") {
- menu.NewMenuBarItem = View ();
- }
- }
- private void MdiMain_Deactivate (Toplevel top)
- {
- workerApp.WriteLog ($"{top.Data} deactivate.");
- }
- private void MdiMain_Activate (Toplevel top)
- {
- workerApp.WriteLog ($"{top.Data} activate.");
- }
- private MenuBarItem View ()
- {
- List<MenuItem> menuItems = new List<MenuItem> ();
- var item = new MenuItem () {
- Title = "WorkerApp",
- CheckType = MenuItemCheckStyle.Checked
- };
- var top = Application.MdiChildes?.Find ((x) => x.Data.ToString () == "WorkerApp");
- if (top != null) {
- item.Checked = top.Visible;
- }
- item.Action += () => {
- var top = Application.MdiChildes.Find ((x) => x.Data.ToString () == "WorkerApp");
- item.Checked = top.Visible = !item.Checked;
- if (top.Visible) {
- top.ShowChild ();
- } else {
- Application.MdiTop.SetNeedsDisplay ();
- }
- };
- menuItems.Add (item);
- return new MenuBarItem ("_View",
- new List<MenuItem []> () { menuItems.Count == 0 ? new MenuItem [] { } : menuItems.ToArray () });
- }
- private MenuBarItem OpenedWindows ()
- {
- var index = 1;
- List<MenuItem> menuItems = new List<MenuItem> ();
- var sortedChildes = Application.MdiChildes;
- sortedChildes.Sort (new ToplevelComparer ());
- foreach (var top in sortedChildes) {
- if (top.Data.ToString () == "WorkerApp" && !top.Visible) {
- continue;
- }
- var item = new MenuItem ();
- item.Title = top is Window ? $"{index} {((Window)top).Title}" : $"{index} {top.Data}";
- index++;
- item.CheckType |= MenuItemCheckStyle.Checked;
- var topTitle = top is Window ? ((Window)top).Title : top.Data.ToString ();
- var itemTitle = item.Title.Substring (index.ToString ().Length + 1);
- if (top == top.GetTopMdiChild () && topTitle == itemTitle) {
- item.Checked = true;
- } else {
- item.Checked = false;
- }
- item.Action += () => {
- top.ShowChild ();
- };
- menuItems.Add (item);
- }
- if (menuItems.Count == 0) {
- return new MenuBarItem ("_Window", "", null);
- } else {
- return new MenuBarItem ("_Window", new List<MenuItem []> () { menuItems.ToArray () });
- }
- }
- private void Quit ()
- {
- RequestStop ();
- }
- }
- class WorkerApp : Toplevel {
- private List<string> log = new List<string> ();
- private ListView listLog;
- private Dictionary<Staging, BackgroundWorker> stagingWorkers;
- private List<StagingUIController> stagingsUI;
- public WorkerApp ()
- {
- Data = "WorkerApp";
- Width = Dim.Percent (80);
- Height = Dim.Percent (50);
- ColorScheme = Colors.Base;
- var label = new Label ("Worker collection Log") {
- X = Pos.Center (),
- Y = 0
- };
- Add (label);
- listLog = new ListView (log) {
- X = 0,
- Y = Pos.Bottom (label),
- Width = Dim.Fill (),
- Height = Dim.Fill ()
- };
- Add (listLog);
- }
- public void RunWorker ()
- {
- var stagingUI = new StagingUIController () { Modal = true };
- Staging staging = null;
- 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.Now}");
- e.Result = stageResult;
- Thread.Sleep (1);
- if (worker.CancellationPending) {
- e.Cancel = true;
- return;
- }
- }
- };
- worker.RunWorkerCompleted += (s, e) => {
- if (e.Error != null) {
- // Failed
- WriteLog ($"Exception occurred {e.Error.Message} on Worker {staging.StartStaging}.{staging.StartStaging:fff} at {DateTime.Now}");
- } else if (e.Cancelled) {
- // Canceled
- WriteLog ($"Worker {staging.StartStaging}.{staging.StartStaging:fff} was canceled at {DateTime.Now}!");
- } else {
- // Passed
- WriteLog ($"Worker {staging.StartStaging}.{staging.StartStaging:fff} was completed at {DateTime.Now}.");
- Application.Refresh ();
- var stagingUI = new StagingUIController (staging, e.Result as List<string>) {
- Modal = false,
- Title = $"Worker started at {staging.StartStaging}.{staging.StartStaging:fff}",
- Data = $"{staging.StartStaging}.{staging.StartStaging:fff}"
- };
- stagingUI.ReportClosed += StagingUI_ReportClosed;
- if (stagingsUI == null) {
- stagingsUI = new List<StagingUIController> ();
- }
- stagingsUI.Add (stagingUI);
- stagingWorkers.Remove (staging);
- stagingUI.Run ();
- }
- };
- Application.Run (stagingUI);
- if (stagingUI.Staging != null && stagingUI.Staging.StartStaging != null) {
- staging = new Staging (stagingUI.Staging.StartStaging);
- WriteLog ($"Worker is started at {staging.StartStaging}.{staging.StartStaging:fff}");
- if (stagingWorkers == null) {
- stagingWorkers = new Dictionary<Staging, BackgroundWorker> ();
- }
- stagingWorkers.Add (staging, worker);
- worker.RunWorkerAsync ();
- stagingUI.Dispose ();
- }
- }
- private void StagingUI_ReportClosed (StagingUIController obj)
- {
- WriteLog ($"Report {obj.Staging.StartStaging}.{obj.Staging.StartStaging:fff} closed.");
- stagingsUI.Remove (obj);
- }
- public void CancelWorker ()
- {
- if (stagingWorkers == null || stagingWorkers.Count == 0) {
- WriteLog ($"Worker is not running at {DateTime.Now}!");
- return;
- }
- foreach (var sw in stagingWorkers) {
- var key = sw.Key;
- var value = sw.Value;
- if (!key.Completed) {
- value.CancelAsync ();
- }
- WriteLog ($"Worker {key.StartStaging}.{key.StartStaging:fff} is canceling at {DateTime.Now}!");
- stagingWorkers.Remove (sw.Key);
- }
- }
- public void WriteLog (string msg)
- {
- log.Add (msg);
- listLog.MoveDown ();
- }
- }
- class StagingUIController : Window {
- private Label label;
- private ListView listView;
- private Button start;
- private Button close;
- public Staging Staging { get; private set; }
- public event Action<StagingUIController> ReportClosed;
- public StagingUIController (Staging staging, List<string> list) : this ()
- {
- Staging = staging;
- label.Text = "Work list:";
- listView.SetSource (list);
- start.Visible = false;
- Id = "";
- }
- public StagingUIController ()
- {
- X = Pos.Center ();
- Y = Pos.Center ();
- Width = Dim.Percent (85);
- Height = Dim.Percent (85);
- ColorScheme = Colors.Dialog;
- 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, ClearOnVisibleFalse = false };
- start.Clicked += () => {
- Staging = new Staging (DateTime.Now);
- RequestStop ();
- };
- Add (start);
- close = new Button ("Close");
- close.Clicked += OnReportClosed;
- Add (close);
- KeyPress += (e) => {
- if (e.KeyEvent.Key == Key.Esc) {
- OnReportClosed ();
- }
- };
- 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);
- };
- }
- private void OnReportClosed ()
- {
- if (Staging?.StartStaging != null) {
- ReportClosed?.Invoke (this);
- }
- RequestStop ();
- }
- public void Run ()
- {
- Application.Run (this);
- }
- }
- class Staging {
- public DateTime? StartStaging { get; private set; }
- public bool Completed { get; }
- public Staging (DateTime? startStaging, bool completed = false)
- {
- StartStaging = startStaging;
- Completed = completed;
- }
- }
- }
- }
|