Browse Source

Some changes in the UICatalog and Scenarios.

BDisp 4 years ago
parent
commit
8d6c2e0aa8

+ 7 - 0
UICatalog/Scenarios/AllViewsTester.cs

@@ -236,7 +236,12 @@ namespace UICatalog {
 			if (view == null) {
 			if (view == null) {
 				return;
 				return;
 			}
 			}
+
+			var layout = view.LayoutStyle;
+
 			try {
 			try {
+				view.LayoutStyle = LayoutStyle.Absolute;
+
 				switch (_xRadioGroup.SelectedItem) {
 				switch (_xRadioGroup.SelectedItem) {
 				case 0:
 				case 0:
 					view.X = Pos.Percent (_xVal);
 					view.X = Pos.Percent (_xVal);
@@ -292,6 +297,8 @@ namespace UICatalog {
 				}
 				}
 			} catch (Exception e) {
 			} catch (Exception e) {
 				MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
 				MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
+			} finally {
+				view.LayoutStyle = layout;
 			}
 			}
 			UpdateTitle (view);
 			UpdateTitle (view);
 		}
 		}

+ 389 - 0
UICatalog/Scenarios/BackgroundWorkerCollection.cs

@@ -0,0 +1,389 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Threading;
+using System.Threading.Tasks;
+using Terminal.Gui;
+
+namespace UICatalog {
+	[ScenarioMetadata (Name: "BackgroundWorker Collection", Description: "A persisting multi Toplevel BackgroundWorker threading")]
+	[ScenarioCategory ("Threading")]
+	[ScenarioCategory ("TopLevel")]
+	[ScenarioCategory ("Dialogs")]
+	[ScenarioCategory ("Controls")]
+	class BackgroundWorkerCollection : Scenario {
+		public override void Init (Toplevel top, ColorScheme colorScheme)
+		{
+			Application.Top.Dispose ();
+
+			Application.Run<MdiMain> ();
+
+			Application.Top.Dispose ();
+		}
+
+		public override void Run ()
+		{
+		}
+
+		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;
+					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.MoveEnd ();
+			}
+		}
+
+		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 };
+				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;
+			}
+		}
+	}
+}

+ 0 - 208
UICatalog/Scenarios/BackgroundWorkerSample.cs

@@ -1,208 +0,0 @@
-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);
-		}
-	}
-}

+ 7 - 2
UICatalog/Scenarios/Buttons.cs

@@ -103,8 +103,13 @@ namespace UICatalog {
 				ColorScheme = Colors.Error
 				ColorScheme = Colors.Error
 			};
 			};
 			Win.Add (removeButton);
 			Win.Add (removeButton);
-			// This in intresting test case because `moveBtn` and below are laid out relative to this one!
-			removeButton.Clicked += () => Win.Remove (removeButton);
+			// This in interesting test case because `moveBtn` and below are laid out relative to this one!
+			removeButton.Clicked += () => {
+				// Now this throw a InvalidOperationException on the TopologicalSort method as is expected.
+				//Win.Remove (removeButton);
+
+				removeButton.Visible = false;
+			};
 
 
 			var computedFrame = new FrameView ("Computed Layout") {
 			var computedFrame = new FrameView ("Computed Layout") {
 				X = 0,
 				X = 0,

+ 187 - 0
UICatalog/Scenarios/SingleBackgroundWorker.cs

@@ -0,0 +1,187 @@
+using System;
+using System.Collections.Generic;
+using System.ComponentModel;
+using System.Threading;
+using Terminal.Gui;
+
+namespace UICatalog {
+	[ScenarioMetadata (Name: "Single BackgroundWorker", Description: "A single BackgroundWorker threading opening another Toplevel")]
+	[ScenarioCategory ("Threading")]
+	[ScenarioCategory ("TopLevel")]
+	[ScenarioCategory ("Dialogs")]
+	[ScenarioCategory ("Controls")]
+	class SingleBackgroundWorker : Scenario {
+		public override void Run ()
+		{
+			Top.Dispose ();
+
+			Application.Run<MainApp> ();
+
+			Top.Dispose ();
+		}
+
+		public class MainApp : Toplevel {
+			private BackgroundWorker worker;
+			private List<string> log = new List<string> ();
+			private DateTime? startStaging;
+			private ListView listLog;
+
+			public MainApp ()
+			{
+				var menu = new MenuBar (new MenuBarItem [] {
+					new MenuBarItem ("_Options", new MenuItem [] {
+						new MenuItem ("_Run Worker", "", () => RunWorker(), null, null, Key.CtrlMask | Key.R),
+						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())
+				});
+				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);
+			}
+
+			public void Load ()
+			{
+				Application.Run (this);
+			}
+
+			private void RunWorker ()
+			{
+				worker = new BackgroundWorker () { WorkerSupportsCancellation = true };
+
+				var cancel = new Button ("Cancel Worker");
+				cancel.Clicked += () => {
+					if (worker == null) {
+						log.Add ($"Worker is not running at {DateTime.Now}!");
+						listLog.SetNeedsDisplay ();
+						return;
+					}
+
+					log.Add ($"Worker {startStaging}.{startStaging:fff} is canceling at {DateTime.Now}!");
+					listLog.SetNeedsDisplay ();
+					worker.CancelAsync ();
+				};
+
+				startStaging = DateTime.Now;
+				log.Add ($"Worker is started at {startStaging}.{startStaging:fff}");
+				listLog.SetNeedsDisplay ();
+
+				var md = new Dialog ($"Running Worker started at {startStaging}.{startStaging:fff}", cancel);
+
+				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 (md.IsCurrentTop) {
+						//Close the dialog
+						Application.RequestStop ();
+					}
+
+					if (e.Error != null) {
+						// Failed
+						log.Add ($"Exception occurred {e.Error.Message} on Worker {startStaging}.{startStaging:fff} at {DateTime.Now}");
+						listLog.SetNeedsDisplay ();
+					} else if (e.Cancelled) {
+						// Canceled
+						log.Add ($"Worker {startStaging}.{startStaging:fff} was canceled at {DateTime.Now}!");
+						listLog.SetNeedsDisplay ();
+					} else {
+						// Passed
+						log.Add ($"Worker {startStaging}.{startStaging:fff} was completed at {DateTime.Now}.");
+						listLog.SetNeedsDisplay ();
+						Application.Refresh ();
+						var builderUI = new StagingUIController (startStaging, e.Result as List<string>);
+						builderUI.Load ();
+					}
+					worker = null;
+				};
+				worker.RunWorkerAsync ();
+				Application.Run (md);
+			}
+		}
+
+		public class StagingUIController : Window {
+			Toplevel top;
+
+			public StagingUIController (DateTime? start, List<string> list)
+			{
+				top = new Toplevel (Application.Top.Frame);
+				top.KeyPress += (e) => {
+					// Prevents Ctrl+Q from closing this.
+					// Only Ctrl+C is allowed.
+					if (e.KeyEvent.Key == (Key.Q | Key.CtrlMask)) {
+						e.Handled = true;
+					}
+				};
+
+				bool Close ()
+				{
+					var n = MessageBox.Query (50, 7, "Close Window.", "Are you sure you want to close this window?", "Yes", "No");
+					return n == 0;
+				}
+
+				var menu = new MenuBar (new MenuBarItem [] {
+					new MenuBarItem ("_Stage", new MenuItem [] {
+						new MenuItem ("_Close", "", () => { if (Close()) { Application.RequestStop(); } }, null, null, Key.CtrlMask | Key.C)
+					})
+				});
+				top.Add (menu);
+
+				var statusBar = new StatusBar (new [] {
+					new StatusItem(Key.CtrlMask | Key.C, "~^C~ Close", () => { if (Close()) { Application.RequestStop(); } }),
+				});
+				top.Add (statusBar);
+
+				Title = $"Worker started at {start}.{start:fff}";
+				Y = 1;
+				Height = Dim.Fill (1);
+
+				ColorScheme = Colors.Base;
+
+				Add (new ListView (list) {
+					X = 0,
+					Y = 0,
+					Width = Dim.Fill (),
+					Height = Dim.Fill ()
+				});
+
+				top.Add (this);
+			}
+
+			public void Load ()
+			{
+				Application.Run (top);
+			}
+		}
+	}
+}

+ 1 - 1
UICatalog/Scenarios/Threading.cs

@@ -89,7 +89,7 @@ namespace UICatalog {
 			var _btnClearData = new Button (80, 20, "Clear Data");
 			var _btnClearData = new Button (80, 20, "Clear Data");
 			_btnClearData.Clicked += () => { _itemsList.Source = null; LogJob ("Cleaning Data"); };
 			_btnClearData.Clicked += () => { _itemsList.Source = null; LogJob ("Cleaning Data"); };
 			var _btnQuit = new Button (80, 22, "Quit");
 			var _btnQuit = new Button (80, 22, "Quit");
-			_btnQuit.Clicked += Application.RequestStop;
+			_btnQuit.Clicked += () => Application.RequestStop ();
 
 
 			Win.Add (_itemsList, _btnActionCancel, _logJob, text, _btnAction, _btnLambda, _btnHandler, _btnSync, _btnMethod, _btnClearData, _btnQuit);
 			Win.Add (_itemsList, _btnActionCancel, _logJob, text, _btnAction, _btnLambda, _btnHandler, _btnSync, _btnMethod, _btnClearData, _btnQuit);
 
 

+ 19 - 6
UICatalog/UICatalog.cs

@@ -65,6 +65,7 @@ namespace UICatalog {
 		private static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
 		private static ConsoleDriver.DiagnosticFlags _diagnosticFlags;
 		private static bool _heightAsBuffer = false;
 		private static bool _heightAsBuffer = false;
 		private static bool _alwaysSetPosition;
 		private static bool _alwaysSetPosition;
+		private static bool _isFirstRunning = true;
 
 
 		static void Main (string [] args)
 		static void Main (string [] args)
 		{
 		{
@@ -108,13 +109,15 @@ namespace UICatalog {
 				scenario.Setup ();
 				scenario.Setup ();
 				scenario.Run ();
 				scenario.Run ();
 
 
-				static void LoadedHandler ()
-				{
-					_rightPane.SetFocus ();
-					_top.Loaded -= LoadedHandler;
-				}
+				//static void LoadedHandler ()
+				//{
+				//	_rightPane.SetFocus ();
+				//	_top.Loaded -= LoadedHandler;
+				//}
 
 
-				_top.Loaded += LoadedHandler;
+				//_top.Loaded += LoadedHandler;
+
+				Application.Shutdown ();
 
 
 #if DEBUG_IDISPOSABLE
 #if DEBUG_IDISPOSABLE
 				// After the scenario runs, validate all Responder-based instances
 				// After the scenario runs, validate all Responder-based instances
@@ -269,11 +272,21 @@ namespace UICatalog {
 			_top.Add (_leftPane);
 			_top.Add (_leftPane);
 			_top.Add (_rightPane);
 			_top.Add (_rightPane);
 			_top.Add (_statusBar);
 			_top.Add (_statusBar);
+
 			_top.Loaded += () => {
 			_top.Loaded += () => {
 				if (_runningScenario != null) {
 				if (_runningScenario != null) {
 					_runningScenario = null;
 					_runningScenario = null;
+					_isFirstRunning = false;
 				}
 				}
 			};
 			};
+			void ReadyHandler ()
+			{
+				if (!_isFirstRunning) {
+					_rightPane.SetFocus ();
+				}
+				_top.Ready -= ReadyHandler;
+			}
+			_top.Ready += ReadyHandler;
 
 
 			Application.Run (_top);
 			Application.Run (_top);
 			return _runningScenario;
 			return _runningScenario;