Bladeren bron

Added Benchmarking to UI Catalog

Tig 9 maanden geleden
bovenliggende
commit
bbf54f4a47
92 gewijzigde bestanden met toevoegingen van 667 en 551 verwijderingen
  1. 26 2
      Terminal.Gui/Application/Application.Screen.cs
  2. 2 0
      Terminal.Gui/Application/Application.cs
  3. 1 0
      Terminal.Gui/ConsoleDrivers/WindowsDriver.cs
  4. 26 0
      UICatalog/BenchmarkResults.cs
  5. 5 5
      UICatalog/Properties/launchSettings.json
  6. 124 7
      UICatalog/Scenario.cs
  7. 2 2
      UICatalog/Scenarios/ASCIICustomButton.cs
  8. 3 3
      UICatalog/Scenarios/Adornments.cs
  9. 37 44
      UICatalog/Scenarios/AllViewsTester.cs
  10. 3 3
      UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs
  11. 4 4
      UICatalog/Scenarios/Arrangement.cs
  12. 2 2
      UICatalog/Scenarios/Bars.cs
  13. 0 105
      UICatalog/Scenarios/Benchmark.cs
  14. 3 3
      UICatalog/Scenarios/Buttons.cs
  15. 6 6
      UICatalog/Scenarios/CharacterMap.cs
  16. 2 2
      UICatalog/Scenarios/ChineseUI.cs
  17. 3 3
      UICatalog/Scenarios/ClassExplorer.cs
  18. 4 4
      UICatalog/Scenarios/Clipping.cs
  19. 9 9
      UICatalog/Scenarios/CollectionNavigatorTester.cs
  20. 3 3
      UICatalog/Scenarios/ColorPicker.cs
  21. 3 3
      UICatalog/Scenarios/CombiningMarks.cs
  22. 3 3
      UICatalog/Scenarios/ComboBoxIteration.cs
  23. 2 2
      UICatalog/Scenarios/ComputedLayout.cs
  24. 5 5
      UICatalog/Scenarios/ConfigurationEditor.cs
  25. 4 4
      UICatalog/Scenarios/ContentScrolling.cs
  26. 2 2
      UICatalog/Scenarios/ContextMenus.cs
  27. 9 9
      UICatalog/Scenarios/CsvEditor.cs
  28. 3 3
      UICatalog/Scenarios/DatePickers.cs
  29. 2 2
      UICatalog/Scenarios/Dialogs.cs
  30. 2 2
      UICatalog/Scenarios/DimAutoDemo.cs
  31. 3 3
      UICatalog/Scenarios/DynamicMenuBar.cs
  32. 2 2
      UICatalog/Scenarios/DynamicStatusBar.cs
  33. 8 8
      UICatalog/Scenarios/Editor.cs
  34. 3 3
      UICatalog/Scenarios/FileDialogExamples.cs
  35. 2 2
      UICatalog/Scenarios/Generic.cs
  36. 3 3
      UICatalog/Scenarios/GraphViewExample.cs
  37. 6 6
      UICatalog/Scenarios/HexEditor.cs
  38. 3 3
      UICatalog/Scenarios/HotKeys.cs
  39. 3 3
      UICatalog/Scenarios/Images.cs
  40. 3 3
      UICatalog/Scenarios/InteractiveTree.cs
  41. 3 3
      UICatalog/Scenarios/InvertColors.cs
  42. 2 2
      UICatalog/Scenarios/KeyBindings.cs
  43. 2 2
      UICatalog/Scenarios/Keys.cs
  44. 4 4
      UICatalog/Scenarios/LineCanvasExperiment.cs
  45. 3 3
      UICatalog/Scenarios/LineDrawing.cs
  46. 4 4
      UICatalog/Scenarios/LineViewExample.cs
  47. 7 7
      UICatalog/Scenarios/ListColumns.cs
  48. 3 3
      UICatalog/Scenarios/ListViewWithSelection.cs
  49. 4 4
      UICatalog/Scenarios/ListsAndCombos.cs
  50. 3 3
      UICatalog/Scenarios/Localization.cs
  51. 3 3
      UICatalog/Scenarios/MenuBarScenario.cs
  52. 3 3
      UICatalog/Scenarios/MessageBoxes.cs
  53. 2 2
      UICatalog/Scenarios/Mouse.cs
  54. 4 4
      UICatalog/Scenarios/MultiColouredTable.cs
  55. 4 4
      UICatalog/Scenarios/Navigation.cs
  56. 4 4
      UICatalog/Scenarios/Notepad.cs
  57. 2 2
      UICatalog/Scenarios/NumericUpDownDemo.cs
  58. 2 2
      UICatalog/Scenarios/PosAlignDemo.cs
  59. 2 2
      UICatalog/Scenarios/ProcessTable.cs
  60. 4 4
      UICatalog/Scenarios/Progress.cs
  61. 4 4
      UICatalog/Scenarios/ProgressBarStyles.cs
  62. 3 3
      UICatalog/Scenarios/RunTExample.cs
  63. 4 4
      UICatalog/Scenarios/RuneWidthGreaterThanOne.cs
  64. 4 4
      UICatalog/Scenarios/Scrolling.cs
  65. 2 2
      UICatalog/Scenarios/SendKeys.cs
  66. 2 2
      UICatalog/Scenarios/ShadowStyles.cs
  67. 2 2
      UICatalog/Scenarios/Shortcuts.cs
  68. 4 4
      UICatalog/Scenarios/SingleBackgroundWorker.cs
  69. 2 2
      UICatalog/Scenarios/Sliders.cs
  70. 3 3
      UICatalog/Scenarios/Snake.cs
  71. 3 3
      UICatalog/Scenarios/SpinnerStyles.cs
  72. 4 4
      UICatalog/Scenarios/SyntaxHighlighting.cs
  73. 3 3
      UICatalog/Scenarios/TabViewExample.cs
  74. 6 6
      UICatalog/Scenarios/TableEditor.cs
  75. 4 4
      UICatalog/Scenarios/Text.cs
  76. 2 2
      UICatalog/Scenarios/TextAlignmentAndDirection.cs
  77. 3 3
      UICatalog/Scenarios/TextEffectsScenario.cs
  78. 2 2
      UICatalog/Scenarios/TextFormatterDemo.cs
  79. 4 4
      UICatalog/Scenarios/TextViewAutocompletePopup.cs
  80. 2 2
      UICatalog/Scenarios/Threading.cs
  81. 3 3
      UICatalog/Scenarios/TileViewNesting.cs
  82. 3 3
      UICatalog/Scenarios/TimeAndDate.cs
  83. 3 3
      UICatalog/Scenarios/TreeUseCases.cs
  84. 4 4
      UICatalog/Scenarios/TreeViewFileSystem.cs
  85. 2 2
      UICatalog/Scenarios/TrueColors.cs
  86. 3 3
      UICatalog/Scenarios/Unicode.cs
  87. 5 5
      UICatalog/Scenarios/ViewExperiments.cs
  88. 2 2
      UICatalog/Scenarios/VkeyPacketSimulator.cs
  89. 2 2
      UICatalog/Scenarios/WindowsAndFrameViews.cs
  90. 2 2
      UICatalog/Scenarios/WizardAsView.cs
  91. 5 5
      UICatalog/Scenarios/Wizards.cs
  92. 169 111
      UICatalog/UICatalog.cs

+ 26 - 2
Terminal.Gui/Application/Application.Screen.cs

@@ -3,13 +3,35 @@ namespace Terminal.Gui;
 
 public static partial class Application // Screen related stuff
 {
+    private static Rectangle? _screen;
+
     /// <summary>
-    ///     Gets the size of the screen. This is the size of the screen as reported by the <see cref="ConsoleDriver"/>.
+    ///     Gets or sets the size of the screen. By default, this is the size of the screen as reported by the <see cref="ConsoleDriver"/>.
     /// </summary>
     /// <remarks>
+    /// <para>
     ///     If the <see cref="ConsoleDriver"/> has not been initialized, this will return a default size of 2048x2048; useful for unit tests.
+    /// </para>
     /// </remarks>
-    public static Rectangle Screen => Driver?.Screen ?? new (new (0, 0), new (2048, 2048));
+    public static Rectangle Screen
+    {
+        get
+        {
+            if (_screen == null)
+            {
+                _screen = Driver?.Screen ?? new (new (0, 0), new (2048, 2048));
+            }
+            return _screen.Value;
+        }
+        set
+        {
+            if (value is {} && (value.X != 0 || value.Y != 0))
+            {
+                throw new NotImplementedException ($"Screen locations other than 0, 0 are not yet supported");
+            }
+            _screen = value;
+        }
+    }
 
     /// <summary>Invoked when the terminal's size changed. The new size of the terminal is provided.</summary>
     /// <remarks>
@@ -33,6 +55,8 @@ public static partial class Application // Screen related stuff
             return false;
         }
 
+        Screen = new (Point.Empty, args.Size.Value);
+
         foreach (Toplevel t in TopLevels)
         {
             t.OnSizeChanging (new (args.Size));

+ 2 - 0
Terminal.Gui/Application/Application.cs

@@ -185,6 +185,8 @@ public static partial class Application
             Driver = null;
         }
 
+        _screen = null;
+
         // Don't reset ForceDriver; it needs to be set before Init is called.
         //ForceDriver = string.Empty;
         //Force16Colors = false;

+ 1 - 0
Terminal.Gui/ConsoleDrivers/WindowsDriver.cs

@@ -1401,6 +1401,7 @@ internal class WindowsDriver : ConsoleDriver
                     Size winSize = WinConsole.GetConsoleOutputWindow (out Point pos);
                     Cols = winSize.Width;
                     Rows = winSize.Height;
+                    OnSizeChanged (new SizeChangedEventArgs (new (Cols, Rows)));
                 }
 
                 WindowsConsole.SmallRect.MakeEmpty (ref _damageRegion);

+ 26 - 0
UICatalog/BenchmarkResults.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Text.Json.Serialization;
+
+namespace UICatalog;
+
+public class BenchmarkResults
+{
+    [JsonInclude]
+    public string Scenario { get; set; }
+
+    [JsonInclude]
+    public TimeSpan Duration { get; set; }
+
+    [JsonInclude]
+    public int IterationCount { get; set; } = 0;
+    [JsonInclude]
+    public int ClearedContentCount { get; set; } = 0;
+    [JsonInclude]
+    public int RefreshedCount { get; set; } = 0;
+    [JsonInclude]
+    public int UpdatedCount { get; set; } = 0;
+    [JsonInclude]
+    public int DrawCompleteCount { get; set; } = 0;
+    [JsonInclude]
+    public int LaidOutCount { get; set; } = 0;
+}

+ 5 - 5
UICatalog/Properties/launchSettings.json

@@ -23,10 +23,6 @@
       "commandLineArgs": "dotnet UICatalog.dll --driver NetDriver",
       "distributionName": ""
     },
-    "Sliders": {
-      "commandName": "Project",
-      "commandLineArgs": "Sliders"
-    },
     "Buttons": {
       "commandName": "Project",
       "commandLineArgs": "Buttons"
@@ -68,11 +64,15 @@
     },
     "Generic": {
       "commandName": "Project",
-      "commandLineArgs": "Generic"
+      "commandLineArgs": "--benchmark Generic"
     },
     "Arrangement": {
       "commandName": "Project",
       "commandLineArgs": "Arrangement"
+    },
+    "Benchmark All": {
+      "commandName": "Project",
+      "commandLineArgs": "--benchmark"
     }
   }
 }

+ 124 - 7
UICatalog/Scenario.cs

@@ -2,8 +2,11 @@
 using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Diagnostics;
 using System.Linq;
 using System.Reflection.Metadata;
+using System.Text;
+using System.Threading;
 using Terminal.Gui;
 
 namespace UICatalog;
@@ -84,7 +87,13 @@ namespace UICatalog;
 public class Scenario : IDisposable
 {
     private static int _maxScenarioNameLen = 30;
-    public string TopLevelColorScheme = "Base";
+    public string TopLevelColorScheme { get; set; } = "Base";
+
+    public BenchmarkResults BenchmarkResults
+    {
+        get { return _benchmarkResults; }
+    }
+
     private bool _disposedValue;
 
     /// <summary>
@@ -142,6 +151,114 @@ public class Scenario : IDisposable
     /// </summary>
     public virtual void Main () { }
 
+    private readonly object _timeoutLock = new ();
+    private object? _timeout;
+    private const uint ABORT_TIME = 1000;
+
+    private Stopwatch? _stopwatch;
+
+    private const uint MAX_ITERATIONS = 500;
+
+    private readonly BenchmarkResults _benchmarkResults = new BenchmarkResults ();
+
+    public void StartBenchmark ()
+    {
+        BenchmarkResults.Scenario = GetName ();
+        Application.InitializedChanged += OnApplicationOnInitializedChanged;
+    }
+
+    public BenchmarkResults EndBenchmark ()
+    {
+        Application.InitializedChanged -= OnApplicationOnInitializedChanged;
+
+        lock (_timeoutLock)
+        {
+            if (_timeout is { })
+            {
+                _timeout = null;
+            }
+        }
+        
+        return _benchmarkResults;
+    }
+
+    private void OnApplicationOnInitializedChanged (object? s, EventArgs<bool> a)
+    {
+        if (a.CurrentValue)
+        {
+            lock (_timeoutLock!)
+            {
+                _timeout = Application.AddTimeout (TimeSpan.FromMilliseconds (ABORT_TIME), ForceCloseCallback);
+            }
+
+            Application.Iteration += OnApplicationOnIteration;
+            Application.Driver!.ClearedContents += (sender, args) => BenchmarkResults.ClearedContentCount++;
+            Application.Driver!.Refreshed += (sender, args) =>
+            {
+                BenchmarkResults.RefreshedCount++;
+
+                if (args.CurrentValue)
+                {
+                    BenchmarkResults.UpdatedCount++;
+                }
+            };
+            Application.NotifyNewRunState += OnApplicationNotifyNewRunState;
+
+            _stopwatch = Stopwatch.StartNew ();
+        }
+        else
+        {
+            Application.NotifyNewRunState -= OnApplicationNotifyNewRunState;
+            Application.Iteration -= OnApplicationOnIteration;
+            BenchmarkResults.Duration = _stopwatch!.Elapsed;
+            _stopwatch?.Stop ();
+        }
+    }
+
+    private void OnApplicationOnIteration (object? s, IterationEventArgs a)
+    {
+        BenchmarkResults.IterationCount++;
+        if (BenchmarkResults.IterationCount > MAX_ITERATIONS)
+        {
+            Application.RequestStop ();
+        }
+    }
+
+    private void OnApplicationNotifyNewRunState (object? sender, RunStateEventArgs e)
+    {
+        // Get a list of all subviews under Application.Top (and their subviews, etc.)
+        // and subscribe to their DrawComplete event
+        void SubscribeAllSubviews (View view)
+        {
+            view.DrawComplete += (s, a) => BenchmarkResults.DrawCompleteCount++;
+            view.SubviewsLaidOut += (s, a) => BenchmarkResults.LaidOutCount++;
+            foreach (View subview in view.Subviews)
+            {
+                SubscribeAllSubviews (subview);
+            }
+        }
+
+        SubscribeAllSubviews (Application.Top!);
+    }
+
+    // If the scenario doesn't close within the abort time, this will force it to quit
+    private bool ForceCloseCallback ()
+    {
+        lock (_timeoutLock)
+        {
+            if (_timeout is { })
+            {
+                _timeout = null;
+            }
+        }
+
+        Console.WriteLine ($@"  Failed to Quit with {Application.QuitKey} after {ABORT_TIME}ms and {BenchmarkResults.IterationCount} iterations. Force quit.");
+
+        Application.RequestStop ();
+
+        return false;
+    }
+
     /// <summary>Gets the Scenario Name + Description with the Description padded based on the longest known Scenario name.</summary>
     /// <returns></returns>
     public override string ToString () { return $"{GetName ().PadRight (_maxScenarioNameLen)}{GetDescription ()}"; }
@@ -183,7 +300,7 @@ public class Scenario : IDisposable
                                                    (current, attrs) => current
                                                                        .Union (
                                                                                attrs.Where (a => a is ScenarioCategory)
-                                                                                    .Select (a => ((ScenarioCategory)a).Name))
+                                                                                    .Select (a => ((Scenario.ScenarioCategory)a).Name))
                                                                        .ToList ());
 
         // Sort
@@ -206,8 +323,8 @@ public class Scenario : IDisposable
         {
             return GetCustomAttributes (t)
                    .ToList ()
-                   .Where (a => a is ScenarioCategory)
-                   .Select (a => ((ScenarioCategory)a).Name)
+                   .Where (a => a is Scenario.ScenarioCategory)
+                   .Select (a => ((Scenario.ScenarioCategory)a).Name)
                    .ToList ();
         }
 
@@ -216,7 +333,7 @@ public class Scenario : IDisposable
         /// <returns>Name of the category</returns>
         public static string GetName (Type t)
         {
-            if (GetCustomAttributes (t).FirstOrDefault (a => a is ScenarioMetadata) is ScenarioMetadata { } metadata)
+            if (GetCustomAttributes (t).FirstOrDefault (a => a is Scenario.ScenarioMetadata) is Scenario.ScenarioMetadata { } metadata)
             {
                 return metadata.Name;
             }
@@ -240,7 +357,7 @@ public class Scenario : IDisposable
         /// <returns></returns>
         public static string GetDescription (Type t)
         {
-            if (GetCustomAttributes (t).FirstOrDefault (a => a is ScenarioMetadata) is ScenarioMetadata { } metadata)
+            if (GetCustomAttributes (t).FirstOrDefault (a => a is Scenario.ScenarioMetadata) is Scenario.ScenarioMetadata { } metadata)
             {
                 return metadata.Description;
             }
@@ -253,7 +370,7 @@ public class Scenario : IDisposable
         /// <returns></returns>
         public static string GetName (Type t)
         {
-            if (GetCustomAttributes (t).FirstOrDefault (a => a is ScenarioMetadata) is ScenarioMetadata { } metadata)
+            if (GetCustomAttributes (t).FirstOrDefault (a => a is Scenario.ScenarioMetadata) is Scenario.ScenarioMetadata { } metadata)
             {
                 return metadata.Name;
             }

+ 2 - 2
UICatalog/Scenarios/ASCIICustomButton.cs

@@ -7,8 +7,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("ASCIICustomButtonTest", "ASCIICustomButton sample")]
-[ScenarioCategory ("Controls")]
+[Scenario.ScenarioMetadata ("ASCIICustomButtonTest", "ASCIICustomButton sample")]
+[Scenario.ScenarioCategory ("Controls")]
 public class ASCIICustomButtonTest : Scenario
 {
     private static bool _smallerWindow;

+ 3 - 3
UICatalog/Scenarios/Adornments.cs

@@ -2,9 +2,9 @@
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Adornments Demo", "Demonstrates Margin, Border, and Padding on Views.")]
-[ScenarioCategory ("Layout")]
-[ScenarioCategory ("Adornments")]
+[Scenario.ScenarioMetadata ("Adornments Demo", "Demonstrates Margin, Border, and Padding on Views.")]
+[Scenario.ScenarioCategory ("Layout")]
+[Scenario.ScenarioCategory ("Adornments")]
 public class Adornments : Scenario
 {
     public override void Main ()

+ 37 - 44
UICatalog/Scenarios/AllViewsTester.cs

@@ -1,34 +1,33 @@
-using System;
+#nullable enable
+using System;
 using System.Collections.Generic;
-using System.Collections.ObjectModel;
 using System.Diagnostics;
 using System.Linq;
-using System.Reflection;
 using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("All Views Tester", "Provides a test UI for all classes derived from View.")]
-[ScenarioCategory ("Layout")]
-[ScenarioCategory ("Tests")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Adornments")]
+[Scenario.ScenarioMetadata ("All Views Tester", "Provides a test UI for all classes derived from View.")]
+[Scenario.ScenarioCategory ("Layout")]
+[Scenario.ScenarioCategory ("Tests")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Adornments")]
 public class AllViewsTester : Scenario
 {
 
-    private Dictionary<string, Type> _viewClasses;
-    private ListView _classListView;
-    private AdornmentsEditor _adornmentsEditor;
+    private Dictionary<string, Type>? _viewClasses;
+    private ListView? _classListView;
+    private AdornmentsEditor? _adornmentsEditor;
 
-    private LayoutEditor _layoutEditor;
-    private FrameView _settingsPane;
-    private RadioGroup _orientation;
+    private LayoutEditor? _layoutEditor;
+    private FrameView? _settingsPane;
+    private RadioGroup? _orientation;
     private string _demoText = "This, that, and the other thing.";
-    private TextView _demoTextView;
+    private TextView? _demoTextView;
 
-    private FrameView _hostPane;
-    private View _curView;
-    private EventLog _eventLog;
+    private FrameView? _hostPane;
+    private View? _curView;
+    private EventLog? _eventLog;
 
     public override void Main ()
     {
@@ -79,7 +78,7 @@ public class AllViewsTester : Scenario
 
         _classListView.Accepting += (sender, args) =>
                                     {
-                                        _curView.SetFocus ();
+                                        _curView?.SetFocus ();
                                         args.Cancel = true;
                                     };
 
@@ -120,7 +119,7 @@ public class AllViewsTester : Scenario
             Title = "Settings [_4]",
             X = Pos.Right (_adornmentsEditor),
             Y = Pos.Bottom (_layoutEditor),
-            Width = Dim.Width(_layoutEditor),
+            Width = Dim.Width (_layoutEditor),
             Height = Dim.Auto (),
             CanFocus = true,
             ColorScheme = Colors.ColorSchemes ["TopLevel"],
@@ -171,7 +170,7 @@ public class AllViewsTester : Scenario
 
         _eventLog = new EventLog ()
         {
-           // X = Pos.Right(_layoutEditor)
+            // X = Pos.Right(_layoutEditor)
         };
         _eventLog.X = Pos.AnchorEnd ();
         _eventLog.Y = 0;
@@ -218,9 +217,9 @@ public class AllViewsTester : Scenario
         Application.Shutdown ();
     }
 
-    private void App_Initialized (object sender, EventArgs e)
+    private void App_Initialized (object? sender, EventArgs e)
     {
-        _classListView.SelectedItem = 0;
+        _classListView!.SelectedItem = 0;
         _classListView.SetFocus ();
     }
 
@@ -246,7 +245,7 @@ public class AllViewsTester : Scenario
         }
 
         // Instantiate view
-        var view = (View)Activator.CreateInstance (type);
+        var view = (View)Activator.CreateInstance (type)!;
         if (view is IDesignable designable)
         {
             designable.EnableForDesign (ref _demoText);
@@ -259,12 +258,12 @@ public class AllViewsTester : Scenario
 
         if (view is IOrientation orientatedView)
         {
-            _orientation.SelectedItem = (int)orientatedView.Orientation;
+            _orientation!.SelectedItem = (int)orientatedView.Orientation;
             _orientation.Enabled = true;
         }
         else
         {
-            _orientation.Enabled = false;
+            _orientation!.Enabled = false;
         }
 
         view.Initialized += CurrentView_Initialized;
@@ -273,9 +272,9 @@ public class AllViewsTester : Scenario
         view.Id = "_curView";
         _curView = view;
 
-        _eventLog.ViewToLog = _curView;
-        _hostPane.Add (_curView);
-        _layoutEditor.ViewToEdit = _curView;
+        _eventLog!.ViewToLog = _curView;
+        _hostPane!.Add (_curView);
+        _layoutEditor!.ViewToEdit = _curView;
         _curView.SetNeedsLayout ();
     }
 
@@ -285,8 +284,8 @@ public class AllViewsTester : Scenario
         {
             _curView.Initialized -= CurrentView_Initialized;
             _curView.SubviewsLaidOut -= CurrentView_LayoutComplete;
-            _hostPane.Remove (_curView);
-            _layoutEditor.ViewToEdit = null;
+            _hostPane!.Remove (_curView);
+            _layoutEditor!.ViewToEdit = null;
 
             _curView.Dispose ();
             _curView = null;
@@ -295,30 +294,24 @@ public class AllViewsTester : Scenario
 
     private static List<Type> GetAllViewClassesCollection ()
     {
-        List<Type> types = new ();
-
-        foreach (Type type in typeof (View).Assembly.GetTypes ()
-                                           .Where (
-                                                   myType =>
-                                                       myType.IsClass && !myType.IsAbstract && myType.IsPublic && myType.IsSubclassOf (typeof (View))
-                                                  ))
-        {
-            types.Add (type);
-        }
+        List<Type> types = typeof (View).Assembly.GetTypes ()
+                                        .Where (myType => myType is { IsClass: true, IsAbstract: false, IsPublic: true }
+                                                          && myType.IsSubclassOf (typeof (View)))
+                                        .ToList ();
 
         types.Add (typeof (View));
 
         return types;
     }
 
-    private void CurrentView_LayoutComplete (object sender, LayoutEventArgs args)
+    private void CurrentView_LayoutComplete (object? sender, LayoutEventArgs args)
     {
         UpdateHostTitle (_curView);
     }
 
-    private void UpdateHostTitle (View view) { _hostPane.Title = $"{view.GetType ().Name} [_0]"; }
+    private void UpdateHostTitle (View? view) { _hostPane!.Title = $"{view!.GetType ().Name} [_0]"; }
 
-    private void CurrentView_Initialized (object sender, EventArgs e)
+    private void CurrentView_Initialized (object? sender, EventArgs e)
     {
         if (sender is not View view)
         {

+ 3 - 3
UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs

@@ -10,9 +10,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Animation", "Demonstration of how to render animated images with threading.")]
-[ScenarioCategory ("Threading")]
-[ScenarioCategory ("Drawing")]
+[Scenario.ScenarioMetadata ("Animation", "Demonstration of how to render animated images with threading.")]
+[Scenario.ScenarioCategory ("Threading")]
+[Scenario.ScenarioCategory ("Drawing")]
 public class AnimationScenario : Scenario
 {
     private bool _isDisposed;

+ 4 - 4
UICatalog/Scenarios/Arrangement.cs

@@ -5,10 +5,10 @@ using Timer = System.Timers.Timer;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Arrangement", "Arrangement Tester")]
-[ScenarioCategory ("Mouse and Keyboard")]
-[ScenarioCategory ("Layout")]
-[ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioMetadata ("Arrangement", "Arrangement Tester")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioCategory ("Layout")]
+[Scenario.ScenarioCategory ("Overlapped")]
 public class Arrangement : Scenario
 {
     private int _hotkeyCount;

+ 2 - 2
UICatalog/Scenarios/Bars.cs

@@ -8,8 +8,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Bars", "Illustrates Bar views (e.g. StatusBar)")]
-[ScenarioCategory ("Controls")]
+[Scenario.ScenarioMetadata ("Bars", "Illustrates Bar views (e.g. StatusBar)")]
+[Scenario.ScenarioCategory ("Controls")]
 public class Bars : Scenario
 {
     public override void Main ()

+ 0 - 105
UICatalog/Scenarios/Benchmark.cs

@@ -1,105 +0,0 @@
-using System;
-using System.Collections.Generic;
-using System.Collections.ObjectModel;
-using System.Diagnostics;
-using System.Linq;
-using System.Reflection;
-using System.Threading.Tasks;
-using Terminal.Gui;
-
-namespace UICatalog.Scenarios;
-
-[ScenarioMetadata ("Benchmark", "Benchmarks Terminal.Gui Layout and Draw Perf.")]
-public sealed class Benchmark : Scenario
-{
-    public override void Main ()
-    {
-        // Init
-        Application.Init ();
-
-        // Setup - Create a top-level application window and configure it.
-        Window appWindow = new ()
-        {
-            Title = GetQuitKeyAndName (),
-        };
-
-        ListView scenarioList = new ListView ()
-        {
-            Title = "_Sceanrios",
-            BorderStyle = LineStyle.Rounded,
-            Width = Dim.Auto (),
-            Height = Dim.Fill (),
-        };
-
-        var types = AllScenarioTypes;
-        ObservableCollection<string> scenarios = new ObservableCollection<string> (AllScenarioTypes.Select (
-                                                                                                       t =>
-                                                                                                       {
-                                                                                                           var attr = t.GetCustomAttributes (
-                                                                                                                    typeof (ScenarioMetadata),
-                                                                                                                    false) [0] as ScenarioMetadata;
-
-                                                                                                           return attr.Name;
-
-                                                                                                       }));
-        scenarioList.Source = new ListWrapper<string> (scenarios);
-
-        scenarioList.Accepting += (sender, args) =>
-                                  {
-
-                                      bool waitForOutput = true;
-                                      var output = string.Empty;
-
-
-
-                                      //Task.Run (
-                                      //  () =>
-                                      //{
-                                      using var process = new Process
-                                      {
-                                          StartInfo = new ()
-                                          {
-                                              FileName = "UICatalog.exe",
-                                              Arguments = $"{scenarios [scenarioList.SelectedItem]}",
-                                              RedirectStandardOutput = false,
-                                              RedirectStandardError = false,
-                                              RedirectStandardInput = false,
-                                              UseShellExecute = true,
-                                              CreateNoWindow = true
-                                          }
-                                      };
-
-                                      process.Start ();
-
-                                      if (!process.WaitForExit (10000))
-                                      {
-                                          var timeoutError =
-                                              $@"Process timed out. Command line: {process.StartInfo.FileName} {process.StartInfo.Arguments}.";
-
-                                          Debug.WriteLine (timeoutError);
-
-                                          process.Close ();
-
-                                          return;
-                                      }
-                                      //   });
-
-                                  };
-
-        appWindow.Add (scenarioList);
-
-        // Run - Start the application.
-        Application.Run (appWindow);
-        appWindow.Dispose ();
-
-        // Shutdown - Calling Application.Shutdown is required.
-        Application.Shutdown ();
-    }
-
-    public static IEnumerable<Type> AllScenarioTypes =>
-        typeof (Scenario).Assembly
-                         .GetTypes ()
-                         .Where (type => type.IsClass && !type.IsAbstract && type.IsSubclassOf (typeof (Scenario)))
-                         .Select (type => type);
-
-}

+ 3 - 3
UICatalog/Scenarios/Buttons.cs

@@ -7,9 +7,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Buttons", "Demonstrates all sorts of Buttons.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Layout")]
+[Scenario.ScenarioMetadata ("Buttons", "Demonstrates all sorts of Buttons.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Layout")]
 public class Buttons : Scenario
 {
     public override void Main ()

+ 6 - 6
UICatalog/Scenarios/CharacterMap.cs

@@ -21,12 +21,12 @@ namespace UICatalog.Scenarios;
 ///     "Character Map" application (like Windows' charmap.exe). - Helps test unicode character rendering in Terminal.Gui -
 ///     Illustrates how to do infinite scrolling
 /// </summary>
-[ScenarioMetadata ("Character Map", "Unicode viewer demonstrating infinite content, scrolling, and Unicode.")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Drawing")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Layout")]
-[ScenarioCategory ("Scrolling")]
+[Scenario.ScenarioMetadata ("Character Map", "Unicode viewer demonstrating infinite content, scrolling, and Unicode.")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Drawing")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Layout")]
+[Scenario.ScenarioCategory ("Scrolling")]
 
 public class CharacterMap : Scenario
 {

+ 2 - 2
UICatalog/Scenarios/ChineseUI.cs

@@ -2,8 +2,8 @@
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("ChineseUI", "Chinese UI")]
-[ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioMetadata ("ChineseUI", "Chinese UI")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
 public class ChineseUI : Scenario
 {
     public override void Main ()

+ 3 - 3
UICatalog/Scenarios/ClassExplorer.cs

@@ -7,9 +7,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Class Explorer", "Tree view explorer for classes by namespace based on TreeView.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("TreeView")]
+[Scenario.ScenarioMetadata ("Class Explorer", "Tree view explorer for classes by namespace based on TreeView.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("TreeView")]
 public class ClassExplorer : Scenario
 {
     private MenuItem _highlightModelTextOnly;

+ 4 - 4
UICatalog/Scenarios/Clipping.cs

@@ -2,10 +2,10 @@
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Clipping", "Used to test that things clip correctly")]
-[ScenarioCategory ("Tests")]
-[ScenarioCategory ("Drawing")]
-[ScenarioCategory ("Scrolling")]
+[Scenario.ScenarioMetadata ("Clipping", "Used to test that things clip correctly")]
+[Scenario.ScenarioCategory ("Tests")]
+[Scenario.ScenarioCategory ("Drawing")]
+[Scenario.ScenarioCategory ("Scrolling")]
 public class Clipping : Scenario
 {
     public override void Main ()

+ 9 - 9
UICatalog/Scenarios/CollectionNavigatorTester.cs

@@ -6,15 +6,15 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata (
-                      "Collection Navigator",
-                      "Demonstrates keyboard navigation in ListView & TreeView (CollectionNavigator)."
-                  )]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("ListView")]
-[ScenarioCategory ("TreeView")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioMetadata (
+                               "Collection Navigator",
+                               "Demonstrates keyboard navigation in ListView & TreeView (CollectionNavigator)."
+                           )]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("ListView")]
+[Scenario.ScenarioCategory ("TreeView")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
 public class CollectionNavigatorTester : Scenario
 {
     private ObservableCollection<string> _items = new ObservableCollection<string> (new ObservableCollection<string> ()

+ 3 - 3
UICatalog/Scenarios/ColorPicker.cs

@@ -3,9 +3,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Color Picker", "Color Picker.")]
-[ScenarioCategory ("Colors")]
-[ScenarioCategory ("Controls")]
+[Scenario.ScenarioMetadata ("Color Picker", "Color Picker.")]
+[Scenario.ScenarioCategory ("Colors")]
+[Scenario.ScenarioCategory ("Controls")]
 public class ColorPickers : Scenario
 {
     /// <summary>Background color Label.</summary>

+ 3 - 3
UICatalog/Scenarios/CombiningMarks.cs

@@ -2,14 +2,14 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Combining Marks", "Illustrates how Unicode Combining Marks work (or don't).")]
-[ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioMetadata ("Combining Marks", "Illustrates how Unicode Combining Marks work (or don't).")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
 public class CombiningMarks : Scenario
 {
     public override void Main ()
     {
         Application.Init ();
-        var top = new Toplevel { ColorScheme = Colors.ColorSchemes [TopLevelColorScheme] };
+        var top = new Toplevel ();
 
         top.DrawComplete += (s, e) =>
                                    {

+ 3 - 3
UICatalog/Scenarios/ComboBoxIteration.cs

@@ -4,9 +4,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("ComboBoxIteration", "ComboBox iteration.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("ComboBox")]
+[Scenario.ScenarioMetadata ("ComboBoxIteration", "ComboBox iteration.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("ComboBox")]
 public class ComboBoxIteration : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/ComputedLayout.cs

@@ -9,8 +9,8 @@ namespace UICatalog.Scenarios;
 /// <summary>
 ///     This Scenario demonstrates how to use Terminal.Gui's Dim and Pos Layout System. 
 /// </summary>
-[ScenarioMetadata ("Computed Layout", "Demonstrates the Computed (Dim and Pos) Layout System.")]
-[ScenarioCategory ("Layout")]
+[Scenario.ScenarioMetadata ("Computed Layout", "Demonstrates the Computed (Dim and Pos) Layout System.")]
+[Scenario.ScenarioCategory ("Layout")]
 public class ComputedLayout : Scenario
 {
     public override void Main ()

+ 5 - 5
UICatalog/Scenarios/ConfigurationEditor.cs

@@ -6,11 +6,11 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Configuration Editor", "Edits Terminal.Gui Config Files.")]
-[ScenarioCategory ("TabView")]
-[ScenarioCategory ("Colors")]
-[ScenarioCategory ("Files and IO")]
-[ScenarioCategory ("TextView")]
+[Scenario.ScenarioMetadata ("Configuration Editor", "Edits Terminal.Gui Config Files.")]
+[Scenario.ScenarioCategory ("TabView")]
+[Scenario.ScenarioCategory ("Colors")]
+[Scenario.ScenarioCategory ("Files and IO")]
+[Scenario.ScenarioCategory ("TextView")]
 public class ConfigurationEditor : Scenario
 {
     private static ColorScheme _editorColorScheme = new ()

+ 4 - 4
UICatalog/Scenarios/ContentScrolling.cs

@@ -5,10 +5,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Content Scrolling", "Demonstrates using View.Viewport and View.GetContentSize () to scroll content.")]
-[ScenarioCategory ("Layout")]
-[ScenarioCategory ("Drawing")]
-[ScenarioCategory ("Scrolling")]
+[Scenario.ScenarioMetadata ("Content Scrolling", "Demonstrates using View.Viewport and View.GetContentSize () to scroll content.")]
+[Scenario.ScenarioCategory ("Layout")]
+[Scenario.ScenarioCategory ("Drawing")]
+[Scenario.ScenarioCategory ("Scrolling")]
 public class ContentScrolling : Scenario
 {
     private ViewDiagnosticFlags _diagnosticFlags;

+ 2 - 2
UICatalog/Scenarios/ContextMenus.cs

@@ -5,8 +5,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("ContextMenus", "Context Menu Sample.")]
-[ScenarioCategory ("Menus")]
+[Scenario.ScenarioMetadata ("ContextMenus", "Context Menu Sample.")]
+[Scenario.ScenarioCategory ("Menus")]
 public class ContextMenus : Scenario
 {
     private readonly List<CultureInfo> _cultureInfos = Application.SupportedCultures;

+ 9 - 9
UICatalog/Scenarios/CsvEditor.cs

@@ -9,15 +9,15 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Csv Editor", "Open and edit simple CSV files using the TableView class.")]
-[ScenarioCategory ("TableView")]
-[ScenarioCategory ("TextView")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Dialogs")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Dialogs")]
-[ScenarioCategory ("Overlapped")]
-[ScenarioCategory ("Files and IO")]
+[Scenario.ScenarioMetadata ("Csv Editor", "Open and edit simple CSV files using the TableView class.")]
+[Scenario.ScenarioCategory ("TableView")]
+[Scenario.ScenarioCategory ("TextView")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Dialogs")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Dialogs")]
+[Scenario.ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioCategory ("Files and IO")]
 public class CsvEditor : Scenario
 {
     private string _currentFile;

+ 3 - 3
UICatalog/Scenarios/DatePickers.cs

@@ -2,9 +2,9 @@
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Date Picker", "Demonstrates how to use DatePicker class")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("DateTime")]
+[Scenario.ScenarioMetadata ("Date Picker", "Demonstrates how to use DatePicker class")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("DateTime")]
 public class DatePickers : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/Dialogs.cs

@@ -5,8 +5,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Dialogs", "Demonstrates how to the Dialog class")]
-[ScenarioCategory ("Dialogs")]
+[Scenario.ScenarioMetadata ("Dialogs", "Demonstrates how to the Dialog class")]
+[Scenario.ScenarioCategory ("Dialogs")]
 public class Dialogs : Scenario
 {
     private static readonly int CODE_POINT = '你'; // We know this is a wide char

+ 2 - 2
UICatalog/Scenarios/DimAutoDemo.cs

@@ -4,8 +4,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("DimAuto", "Demonstrates Dim.Auto")]
-[ScenarioCategory ("Layout")]
+[Scenario.ScenarioMetadata ("DimAuto", "Demonstrates Dim.Auto")]
+[Scenario.ScenarioCategory ("Layout")]
 public class DimAutoDemo : Scenario
 {
     public override void Main ()

+ 3 - 3
UICatalog/Scenarios/DynamicMenuBar.cs

@@ -8,9 +8,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Dynamic MenuBar", "Demonstrates how to change a MenuBar dynamically.")]
-[ScenarioCategory ("Overlapped")]
-[ScenarioCategory ("Menus")]
+[Scenario.ScenarioMetadata ("Dynamic MenuBar", "Demonstrates how to change a MenuBar dynamically.")]
+[Scenario.ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioCategory ("Menus")]
 public class DynamicMenuBar : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/DynamicStatusBar.cs

@@ -9,8 +9,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Dynamic StatusBar", "Demonstrates how to add and remove a StatusBar and change items dynamically.")]
-[ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioMetadata ("Dynamic StatusBar", "Demonstrates how to add and remove a StatusBar and change items dynamically.")]
+[Scenario.ScenarioCategory ("Overlapped")]
 public class DynamicStatusBar : Scenario
 {
     public override void Main ()

+ 8 - 8
UICatalog/Scenarios/Editor.cs

@@ -12,14 +12,14 @@ using static UICatalog.Scenarios.DynamicMenuBar;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Editor", "A Text Editor using the TextView control.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Dialogs")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Overlapped")]
-[ScenarioCategory ("Files and IO")]
-[ScenarioCategory ("TextView")]
-[ScenarioCategory ("Menus")]
+[Scenario.ScenarioMetadata ("Editor", "A Text Editor using the TextView control.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Dialogs")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioCategory ("Files and IO")]
+[Scenario.ScenarioCategory ("TextView")]
+[Scenario.ScenarioCategory ("Menus")]
 public class Editor : Scenario
 {
     private Window _appWindow;

+ 3 - 3
UICatalog/Scenarios/FileDialogExamples.cs

@@ -7,9 +7,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("FileDialog", "Demonstrates how to the FileDialog class")]
-[ScenarioCategory ("Dialogs")]
-[ScenarioCategory ("Files and IO")]
+[Scenario.ScenarioMetadata ("FileDialog", "Demonstrates how to the FileDialog class")]
+[Scenario.ScenarioCategory ("Dialogs")]
+[Scenario.ScenarioCategory ("Files and IO")]
 public class FileDialogExamples : Scenario
 {
     private CheckBox _cbAllowMultipleSelection;

+ 2 - 2
UICatalog/Scenarios/Generic.cs

@@ -2,8 +2,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Generic", "Generic sample - A template for creating new Scenarios")]
-[ScenarioCategory ("Controls")]
+[Scenario.ScenarioMetadata ("Generic", "Generic sample - A template for creating new Scenarios")]
+[Scenario.ScenarioCategory ("Controls")]
 public sealed class Generic : Scenario
 {
     public override void Main ()

+ 3 - 3
UICatalog/Scenarios/GraphViewExample.cs

@@ -8,9 +8,9 @@ using Application = Terminal.Gui.Application;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Graph View", "Demos the GraphView control.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Drawing")]
+[Scenario.ScenarioMetadata ("Graph View", "Demos the GraphView control.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Drawing")]
 public class GraphViewExample : Scenario
 {
     private readonly Thickness _thickness = new (1, 1, 1, 1);

+ 6 - 6
UICatalog/Scenarios/HexEditor.cs

@@ -4,12 +4,12 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("HexEditor", "A binary (hex) editor using the HexView control.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Dialogs")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Overlapped")]
-[ScenarioCategory ("Files and IO")]
+[Scenario.ScenarioMetadata ("HexEditor", "A binary (hex) editor using the HexView control.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Dialogs")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioCategory ("Files and IO")]
 public class HexEditor : Scenario
 {
     private string _fileName = "demo.bin";

+ 3 - 3
UICatalog/Scenarios/HotKeys.cs

@@ -2,9 +2,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("HotKeys", "Demonstrates how HotKeys work.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioMetadata ("HotKeys", "Demonstrates how HotKeys work.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
 public class HotKeys : Scenario
 {
     public override void Main ()

+ 3 - 3
UICatalog/Scenarios/Images.cs

@@ -10,9 +10,9 @@ using Color = Terminal.Gui.Color;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Images", "Demonstration of how to render an image with/without true color support.")]
-[ScenarioCategory ("Colors")]
-[ScenarioCategory ("Drawing")]
+[Scenario.ScenarioMetadata ("Images", "Demonstration of how to render an image with/without true color support.")]
+[Scenario.ScenarioCategory ("Colors")]
+[Scenario.ScenarioCategory ("Drawing")]
 public class Images : Scenario
 {
     public override void Main ()

+ 3 - 3
UICatalog/Scenarios/InteractiveTree.cs

@@ -3,9 +3,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Interactive Tree", "Create nodes and child nodes in TreeView.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("TreeView")]
+[Scenario.ScenarioMetadata ("Interactive Tree", "Create nodes and child nodes in TreeView.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("TreeView")]
 public class InteractiveTree : Scenario
 {
     private TreeView _treeView;

+ 3 - 3
UICatalog/Scenarios/InvertColors.cs

@@ -5,9 +5,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Invert Colors", "Invert the foreground and the background colors.")]
-[ScenarioCategory ("Colors")]
-[ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioMetadata ("Invert Colors", "Invert the foreground and the background colors.")]
+[Scenario.ScenarioCategory ("Colors")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
 public class InvertColors : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/KeyBindings.cs

@@ -7,8 +7,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("KeyBindings", "Illustrates the KeyBindings API.")]
-[ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioMetadata ("KeyBindings", "Illustrates the KeyBindings API.")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
 public sealed class KeyBindings : Scenario
 {
     private readonly ObservableCollection<string> _focusedBindings = [];

+ 2 - 2
UICatalog/Scenarios/Keys.cs

@@ -3,8 +3,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Keys", "Shows keyboard input handling.")]
-[ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioMetadata ("Keys", "Shows keyboard input handling.")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
 public class Keys : Scenario
 {
     public override void Main ()

+ 4 - 4
UICatalog/Scenarios/LineCanvasExperiment.cs

@@ -2,10 +2,10 @@
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("LineCanvas Experiments", "Experiments with LineCanvas")]
-[ScenarioCategory ("Drawing")]
-[ScenarioCategory ("Adornments")]
-[ScenarioCategory ("Proof of Concept")]
+[Scenario.ScenarioMetadata ("LineCanvas Experiments", "Experiments with LineCanvas")]
+[Scenario.ScenarioCategory ("Drawing")]
+[Scenario.ScenarioCategory ("Adornments")]
+[Scenario.ScenarioCategory ("Proof of Concept")]
 public class LineCanvasExperiment : Scenario
 {
     public override void Main ()

+ 3 - 3
UICatalog/Scenarios/LineDrawing.cs

@@ -101,9 +101,9 @@ internal class DrawLineTool : ITool
     }
 }
 
-[ScenarioMetadata ("Line Drawing", "Demonstrates LineCanvas.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Drawing")]
+[Scenario.ScenarioMetadata ("Line Drawing", "Demonstrates LineCanvas.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Drawing")]
 public class LineDrawing : Scenario
 {
     public override void Main ()

+ 4 - 4
UICatalog/Scenarios/LineViewExample.cs

@@ -4,10 +4,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Line View", "Demonstrates drawing lines using the LineView control.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("LineView")]
-[ScenarioCategory ("Adornments")]
+[Scenario.ScenarioMetadata ("Line View", "Demonstrates drawing lines using the LineView control.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("LineView")]
+[Scenario.ScenarioCategory ("Adornments")]
 public class LineViewExample : Scenario
 {
     public override void Main ()

+ 7 - 7
UICatalog/Scenarios/ListColumns.cs

@@ -6,13 +6,13 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("ListColumns", "Implements a columned list via a data table.")]
-[ScenarioCategory ("TableView")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Dialogs")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Overlapped")]
-[ScenarioCategory ("Scrolling")]
+[Scenario.ScenarioMetadata ("ListColumns", "Implements a columned list via a data table.")]
+[Scenario.ScenarioCategory ("TableView")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Dialogs")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioCategory ("Scrolling")]
 public class ListColumns : Scenario
 {
     private ColorScheme _alternatingColorScheme;

+ 3 - 3
UICatalog/Scenarios/ListViewWithSelection.cs

@@ -10,9 +10,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("List View With Selection", "ListView with columns and selection")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("ListView")]
+[Scenario.ScenarioMetadata ("List View With Selection", "ListView with columns and selection")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("ListView")]
 public class ListViewWithSelection : Scenario
 {
     private CheckBox _allowMarkingCB;

+ 4 - 4
UICatalog/Scenarios/ListsAndCombos.cs

@@ -6,10 +6,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("ListView & ComboBox", "Demonstrates a ListView populating a ComboBox that acts as a filter.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("ListView")]
-[ScenarioCategory ("ComboBox")]
+[Scenario.ScenarioMetadata ("ListView & ComboBox", "Demonstrates a ListView populating a ComboBox that acts as a filter.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("ListView")]
+[Scenario.ScenarioCategory ("ComboBox")]
 public class ListsAndCombos : Scenario
 {
     public override void Main ()

+ 3 - 3
UICatalog/Scenarios/Localization.cs

@@ -6,9 +6,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Localization", "Test for localization resources.")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Tests")]
+[Scenario.ScenarioMetadata ("Localization", "Test for localization resources.")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Tests")]
 public class Localization : Scenario
 {
     private CheckBox _allowAnyCheckBox;

+ 3 - 3
UICatalog/Scenarios/MenuBarScenario.cs

@@ -4,9 +4,9 @@ using static System.Runtime.InteropServices.JavaScript.JSType;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("MenuBar", "Demonstrates the MenuBar using the demo menu.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Menus")]
+[Scenario.ScenarioMetadata ("MenuBar", "Demonstrates the MenuBar using the demo menu.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Menus")]
 public class MenuBarScenario : Scenario
 {
     private Label _currentMenuBarItem;

+ 3 - 3
UICatalog/Scenarios/MessageBoxes.cs

@@ -4,9 +4,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("MessageBoxes", "Demonstrates how to use the MessageBox class.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Dialogs")]
+[Scenario.ScenarioMetadata ("MessageBoxes", "Demonstrates how to use the MessageBox class.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Dialogs")]
 public class MessageBoxes : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/Mouse.cs

@@ -6,8 +6,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Mouse", "Demonstrates how to capture mouse events")]
-[ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioMetadata ("Mouse", "Demonstrates how to capture mouse events")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
 public class Mouse : Scenario
 {
     public override void Main ()

+ 4 - 4
UICatalog/Scenarios/MultiColouredTable.cs

@@ -5,10 +5,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("MultiColouredTable", "Demonstrates how to multi color cell contents.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Colors")]
-[ScenarioCategory ("TableView")]
+[Scenario.ScenarioMetadata ("MultiColouredTable", "Demonstrates how to multi color cell contents.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Colors")]
+[Scenario.ScenarioCategory ("TableView")]
 public class MultiColouredTable : Scenario
 {
     private DataTable _table;

+ 4 - 4
UICatalog/Scenarios/Navigation.cs

@@ -3,10 +3,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Navigation", "Navigation Tester")]
-[ScenarioCategory ("Mouse and Keyboard")]
-[ScenarioCategory ("Layout")]
-[ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioMetadata ("Navigation", "Navigation Tester")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioCategory ("Layout")]
+[Scenario.ScenarioCategory ("Overlapped")]
 public class Navigation : Scenario
 {
     private int _hotkeyCount;

+ 4 - 4
UICatalog/Scenarios/Notepad.cs

@@ -4,10 +4,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Notepad", "Multi-tab text editor using the TabView control.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("TabView")]
-[ScenarioCategory ("TextView")]
+[Scenario.ScenarioMetadata ("Notepad", "Multi-tab text editor using the TabView control.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("TabView")]
+[Scenario.ScenarioCategory ("TextView")]
 public class Notepad : Scenario
 {
     private TabView _focusedTabView;

+ 2 - 2
UICatalog/Scenarios/NumericUpDownDemo.cs

@@ -4,8 +4,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("NumericUpDown", "Demonstrates the NumericUpDown View")]
-[ScenarioCategory ("Controls")]
+[Scenario.ScenarioMetadata ("NumericUpDown", "Demonstrates the NumericUpDown View")]
+[Scenario.ScenarioCategory ("Controls")]
 public class NumericUpDownDemo : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/PosAlignDemo.cs

@@ -5,8 +5,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Pos.Align", "Demonstrates Pos.Align")]
-[ScenarioCategory ("Layout")]
+[Scenario.ScenarioMetadata ("Pos.Align", "Demonstrates Pos.Align")]
+[Scenario.ScenarioCategory ("Layout")]
 public sealed class PosAlignDemo : Scenario
 {
     private readonly Aligner _horizAligner = new () { AlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems};

+ 2 - 2
UICatalog/Scenarios/ProcessTable.cs

@@ -5,8 +5,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("ProcessTable", "Demonstrates TableView with the currently running processes.")]
-[ScenarioCategory ("TableView")]
+[Scenario.ScenarioMetadata ("ProcessTable", "Demonstrates TableView with the currently running processes.")]
+[Scenario.ScenarioCategory ("TableView")]
 public class ProcessTable : Scenario
 {
     private TableView tableView;

+ 4 - 4
UICatalog/Scenarios/Progress.cs

@@ -9,10 +9,10 @@ namespace UICatalog.Scenarios;
 // 
 // This would be a great scenario to show of threading (Issue #471)
 //
-[ScenarioMetadata ("Progress", "Shows off ProgressBar and Threading.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Threading")]
-[ScenarioCategory ("Progress")]
+[Scenario.ScenarioMetadata ("Progress", "Shows off ProgressBar and Threading.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Threading")]
+[Scenario.ScenarioCategory ("Progress")]
 public class Progress : Scenario
 {
     private Window win;

+ 4 - 4
UICatalog/Scenarios/ProgressBarStyles.cs

@@ -9,10 +9,10 @@ using static UICatalog.Scenarios.Adornments;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("ProgressBar Styles", "Shows the ProgressBar Styles.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Progress")]
-[ScenarioCategory ("Threading")]
+[Scenario.ScenarioMetadata ("ProgressBar Styles", "Shows the ProgressBar Styles.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Progress")]
+[Scenario.ScenarioCategory ("Threading")]
 
 // TODO: Add enable/disable to show that that is working
 // TODO: Clean up how FramesEditor works 

+ 3 - 3
UICatalog/Scenarios/RunTExample.cs

@@ -2,9 +2,9 @@
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Run<T> Example", "Illustrates using Application.Run<T> to run a custom class")]
-[ScenarioCategory ("Runnable")]
-[ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioMetadata ("Run<T> Example", "Illustrates using Application.Run<T> to run a custom class")]
+[Scenario.ScenarioCategory ("Runnable")]
+[Scenario.ScenarioCategory ("Overlapped")]
 public class RunTExample : Scenario
 {
     public override void Main ()

+ 4 - 4
UICatalog/Scenarios/RuneWidthGreaterThanOne.cs

@@ -3,10 +3,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("RuneWidthGreaterThanOne", "Test rune width greater than one")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Tests")]
+[Scenario.ScenarioMetadata ("RuneWidthGreaterThanOne", "Test rune width greater than one")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Tests")]
 public class RuneWidthGreaterThanOne : Scenario
 {
     private Button _button;

+ 4 - 4
UICatalog/Scenarios/Scrolling.cs

@@ -3,10 +3,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Scrolling", "Demonstrates scrolling etc...")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Scrolling")]
-[ScenarioCategory ("Tests")]
+[Scenario.ScenarioMetadata ("Scrolling", "Demonstrates scrolling etc...")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Scrolling")]
+[Scenario.ScenarioCategory ("Tests")]
 public class Scrolling : Scenario
 {
     private ViewDiagnosticFlags _diagnosticFlags;

+ 2 - 2
UICatalog/Scenarios/SendKeys.cs

@@ -3,8 +3,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("SendKeys", "SendKeys sample - Send key combinations.")]
-[ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioMetadata ("SendKeys", "SendKeys sample - Send key combinations.")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
 public class SendKeys : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/ShadowStyles.cs

@@ -7,8 +7,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("ShadowStyles Demo", "Demonstrates ShadowStyles Effects.")]
-[ScenarioCategory ("Layout")]
+[Scenario.ScenarioMetadata ("ShadowStyles Demo", "Demonstrates ShadowStyles Effects.")]
+[Scenario.ScenarioCategory ("Layout")]
 public class ShadowStyles : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/Shortcuts.cs

@@ -11,8 +11,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Shortcuts", "Illustrates Shortcut class.")]
-[ScenarioCategory ("Controls")]
+[Scenario.ScenarioMetadata ("Shortcuts", "Illustrates Shortcut class.")]
+[Scenario.ScenarioCategory ("Controls")]
 public class Shortcuts : Scenario
 {
     public override void Main ()

+ 4 - 4
UICatalog/Scenarios/SingleBackgroundWorker.cs

@@ -7,10 +7,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Single BackgroundWorker", "A single BackgroundWorker threading opening another Toplevel")]
-[ScenarioCategory ("Threading")]
-[ScenarioCategory ("Overlapped")]
-[ScenarioCategory ("Runnable")]
+[Scenario.ScenarioMetadata ("Single BackgroundWorker", "A single BackgroundWorker threading opening another Toplevel")]
+[Scenario.ScenarioCategory ("Threading")]
+[Scenario.ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioCategory ("Runnable")]
 public class SingleBackgroundWorker : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/Sliders.cs

@@ -8,8 +8,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Sliders", "Demonstrates the Slider view.")]
-[ScenarioCategory ("Controls")]
+[Scenario.ScenarioMetadata ("Sliders", "Demonstrates the Slider view.")]
+[Scenario.ScenarioCategory ("Controls")]
 public class Sliders : Scenario
 {
     public void MakeSliders (View v, List<object> options)

+ 3 - 3
UICatalog/Scenarios/Snake.cs

@@ -8,9 +8,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Snake", "The game of apple eating.")]
-[ScenarioCategory ("Colors")]
-[ScenarioCategory ("Drawing")]
+[Scenario.ScenarioMetadata ("Snake", "The game of apple eating.")]
+[Scenario.ScenarioCategory ("Colors")]
+[Scenario.ScenarioCategory ("Drawing")]
 public class Snake : Scenario
 {
     private bool isDisposed;

+ 3 - 3
UICatalog/Scenarios/SpinnerStyles.cs

@@ -6,9 +6,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("SpinnerView Styles", "Shows the SpinnerView Styles.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Progress")]
+[Scenario.ScenarioMetadata ("SpinnerView Styles", "Shows the SpinnerView Styles.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Progress")]
 public class SpinnerViewStyles : Scenario
 {
     public override void Main ()

+ 4 - 4
UICatalog/Scenarios/SyntaxHighlighting.cs

@@ -11,10 +11,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Syntax Highlighting", "Text editor with keyword highlighting using the TextView control.")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("TextView")]
+[Scenario.ScenarioMetadata ("Syntax Highlighting", "Text editor with keyword highlighting using the TextView control.")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("TextView")]
 public class SyntaxHighlighting : Scenario
 {
     private readonly HashSet<string> _keywords = new (StringComparer.CurrentCultureIgnoreCase)

+ 3 - 3
UICatalog/Scenarios/TabViewExample.cs

@@ -4,9 +4,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Tab View", "Demos TabView control with limited screen space in Absolute layout.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("TabView")]
+[Scenario.ScenarioMetadata ("Tab View", "Demos TabView control with limited screen space in Absolute layout.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("TabView")]
 public class TabViewExample : Scenario
 {
     private MenuItem _miShowBorder;

+ 6 - 6
UICatalog/Scenarios/TableEditor.cs

@@ -9,12 +9,12 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("TableEditor", "Implements data table editor using the TableView control.")]
-[ScenarioCategory ("TableView")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Dialogs")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioMetadata ("TableEditor", "Implements data table editor using the TableView control.")]
+[Scenario.ScenarioCategory ("TableView")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Dialogs")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Overlapped")]
 public class TableEditor : Scenario
 {
     private readonly HashSet<FileSystemInfo> _checkedFileSystemInfos = new ();

+ 4 - 4
UICatalog/Scenarios/Text.cs

@@ -9,10 +9,10 @@ using Terminal.Gui.TextValidateProviders;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Text Input Controls", "Tests all text input controls")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Mouse and Keyboard")]
-[ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioMetadata ("Text Input Controls", "Tests all text input controls")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
 public class Text : Scenario
 {
     private Label _labelMirroringTimeField;

+ 2 - 2
UICatalog/Scenarios/TextAlignmentAndDirection.cs

@@ -6,8 +6,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Text Alignment and Direction", "Demos horizontal and vertical text alignment and direction.")]
-[ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioMetadata ("Text Alignment and Direction", "Demos horizontal and vertical text alignment and direction.")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
 public class TextAlignmentAndDirection : Scenario
 {
     public override void Main ()

+ 3 - 3
UICatalog/Scenarios/TextEffectsScenario.cs

@@ -3,9 +3,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Text Effects", "Text Effects.")]
-[ScenarioCategory ("Colors")]
-[ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioMetadata ("Text Effects", "Text Effects.")]
+[Scenario.ScenarioCategory ("Colors")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
 public class TextEffectsScenario : Scenario
 {
     private TabView _tabView;

+ 2 - 2
UICatalog/Scenarios/TextFormatterDemo.cs

@@ -6,8 +6,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("TextFormatter Demo", "Demos and tests the TextFormatter class.")]
-[ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioMetadata ("TextFormatter Demo", "Demos and tests the TextFormatter class.")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
 public class TextFormatterDemo : Scenario
 {
     public override void Main ()

+ 4 - 4
UICatalog/Scenarios/TextViewAutocompletePopup.cs

@@ -4,10 +4,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("TextView Autocomplete Popup", "Shows five TextView Autocomplete Popup effects")]
-[ScenarioCategory ("TextView")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioMetadata ("TextView Autocomplete Popup", "Shows five TextView Autocomplete Popup effects")]
+[Scenario.ScenarioCategory ("TextView")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
 public class TextViewAutocompletePopup : Scenario
 {
     private int _height = 10;

+ 2 - 2
UICatalog/Scenarios/Threading.cs

@@ -6,8 +6,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Threading", "Demonstration of how to use threading in different ways")]
-[ScenarioCategory ("Threading")]
+[Scenario.ScenarioMetadata ("Threading", "Demonstration of how to use threading in different ways")]
+[Scenario.ScenarioCategory ("Threading")]
 public class Threading : Scenario
 {
     private readonly ObservableCollection<string> _log = [];

+ 3 - 3
UICatalog/Scenarios/TileViewNesting.cs

@@ -3,9 +3,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Tile View Nesting", "Demonstrates recursive nesting of TileViews")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("LineView")]
+[Scenario.ScenarioMetadata ("Tile View Nesting", "Demonstrates recursive nesting of TileViews")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("LineView")]
 public class TileViewNesting : Scenario
 {
     private CheckBox _cbBorder;

+ 3 - 3
UICatalog/Scenarios/TimeAndDate.cs

@@ -3,9 +3,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Time And Date", "Illustrates TimeField and time & date handling")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("DateTime")]
+[Scenario.ScenarioMetadata ("Time And Date", "Illustrates TimeField and time & date handling")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("DateTime")]
 public class TimeAndDate : Scenario
 {
     private Label _lblDateFmt;

+ 3 - 3
UICatalog/Scenarios/TreeUseCases.cs

@@ -4,9 +4,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Tree View", "Simple tree view examples.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("TreeView")]
+[Scenario.ScenarioMetadata ("Tree View", "Simple tree view examples.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("TreeView")]
 public class TreeUseCases : Scenario
 {
     private View _currentTree;

+ 4 - 4
UICatalog/Scenarios/TreeViewFileSystem.cs

@@ -7,10 +7,10 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("File System Explorer", "Hierarchical file system explorer demonstrating TreeView.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("TreeView")]
-[ScenarioCategory ("Files and IO")]
+[Scenario.ScenarioMetadata ("File System Explorer", "Hierarchical file system explorer demonstrating TreeView.")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("TreeView")]
+[Scenario.ScenarioCategory ("Files and IO")]
 public class TreeViewFileSystem : Scenario
 {
     private readonly FileSystemIconProvider _iconProvider = new ();

+ 2 - 2
UICatalog/Scenarios/TrueColors.cs

@@ -3,8 +3,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("True Colors", "Demonstration of true color support.")]
-[ScenarioCategory ("Colors")]
+[Scenario.ScenarioMetadata ("True Colors", "Demonstration of true color support.")]
+[Scenario.ScenarioCategory ("Colors")]
 public class TrueColors : Scenario
 {
     public override void Main ()

+ 3 - 3
UICatalog/Scenarios/Unicode.cs

@@ -5,9 +5,9 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Unicode", "Tries to test Unicode in all controls (#204)")]
-[ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Controls")]
+[Scenario.ScenarioMetadata ("Unicode", "Tries to test Unicode in all controls (#204)")]
+[Scenario.ScenarioCategory ("Text and Formatting")]
+[Scenario.ScenarioCategory ("Controls")]
 public class UnicodeInMenu : Scenario
 {
     public override void Main ()

+ 5 - 5
UICatalog/Scenarios/ViewExperiments.cs

@@ -3,11 +3,11 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("View Experiments", "v2 View Experiments")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Adornments")]
-[ScenarioCategory ("Layout")]
-[ScenarioCategory ("Proof of Concept")]
+[Scenario.ScenarioMetadata ("View Experiments", "v2 View Experiments")]
+[Scenario.ScenarioCategory ("Controls")]
+[Scenario.ScenarioCategory ("Adornments")]
+[Scenario.ScenarioCategory ("Layout")]
+[Scenario.ScenarioCategory ("Proof of Concept")]
 public class ViewExperiments : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/VkeyPacketSimulator.cs

@@ -7,8 +7,8 @@ using Terminal.Gui.ConsoleDrivers;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("VkeyPacketSimulator", "Simulates the Virtual Key Packet")]
-[ScenarioCategory ("Mouse and Keyboard")]
+[Scenario.ScenarioMetadata ("VkeyPacketSimulator", "Simulates the Virtual Key Packet")]
+[Scenario.ScenarioCategory ("Mouse and Keyboard")]
 public class VkeyPacketSimulator : Scenario
 {
     private static readonly ManualResetEventSlim _stopOutput = new (false);

+ 2 - 2
UICatalog/Scenarios/WindowsAndFrameViews.cs

@@ -4,8 +4,8 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Windows & FrameViews", "Stress Tests Windows, sub-Windows, and FrameViews.")]
-[ScenarioCategory ("Layout")]
+[Scenario.ScenarioMetadata ("Windows & FrameViews", "Stress Tests Windows, sub-Windows, and FrameViews.")]
+[Scenario.ScenarioCategory ("Layout")]
 public class WindowsAndFrameViews : Scenario
 {
     public override void Main ()

+ 2 - 2
UICatalog/Scenarios/WizardAsView.cs

@@ -2,8 +2,8 @@
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("WizardAsView", "Shows using the Wizard class in an non-modal way")]
-[ScenarioCategory ("Wizards")]
+[Scenario.ScenarioMetadata ("WizardAsView", "Shows using the Wizard class in an non-modal way")]
+[Scenario.ScenarioCategory ("Wizards")]
 public class WizardAsView : Scenario
 {
     public override void Main ()

+ 5 - 5
UICatalog/Scenarios/Wizards.cs

@@ -4,11 +4,11 @@ using Terminal.Gui;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Wizards", "Demonstrates the Wizard class")]
-[ScenarioCategory ("Dialogs")]
-[ScenarioCategory ("Overlapped")]
-[ScenarioCategory ("Wizards")]
-[ScenarioCategory ("Runnable")]
+[Scenario.ScenarioMetadata ("Wizards", "Demonstrates the Wizard class")]
+[Scenario.ScenarioCategory ("Dialogs")]
+[Scenario.ScenarioCategory ("Overlapped")]
+[Scenario.ScenarioCategory ("Wizards")]
+[Scenario.ScenarioCategory ("Runnable")]
 
 public class Wizards : Scenario
 {

+ 169 - 111
UICatalog/UICatalog.cs

@@ -4,6 +4,7 @@ using System;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.CommandLine;
+using System.Data;
 using System.Diagnostics;
 using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
@@ -12,6 +13,7 @@ using System.Linq;
 using System.Reflection;
 using System.Runtime.InteropServices;
 using System.Text;
+using System.Text.Json;
 using System.Text.Json.Serialization;
 using Terminal.Gui;
 using UICatalog.Scenarios;
@@ -127,7 +129,7 @@ public class UICatalogApp
         _categories = Scenario.GetAllCategories ();
 
         // Process command line args
-        // "UICatalog [-driver <driver>] [scenario name]"
+        // "UICatalog [--driver <driver>] [--benchmark] [scenario name]"
         // If no driver is provided, the default driver is used.
         Option<string> driverOption = new Option<string> ("--driver", "The ConsoleDriver to use.").FromAmong (
              Application.GetDriverTypes ()
@@ -138,6 +140,10 @@ public class UICatalogApp
         driverOption.AddAlias ("-d");
         driverOption.AddAlias ("--d");
 
+        Option<bool> benchmarkFlag = new Option<bool> ("--benchmark", "Enables benchmarking.");
+        benchmarkFlag.AddAlias ("-b");
+        benchmarkFlag.AddAlias ("--b");
+
         Argument<string> scenarioArgument = new Argument<string> (
                                                                   "scenario",
                                                                   description: "The name of the scenario to run.",
@@ -148,8 +154,9 @@ public class UICatalogApp
                                                                                         .ToArray ()
                                                                              );
 
+
         var rootCommand =
-            new RootCommand ("A comprehensive sample library for Terminal.Gui") { scenarioArgument, driverOption };
+            new RootCommand ("A comprehensive sample library for Terminal.Gui") { scenarioArgument, benchmarkFlag, driverOption };
 
         rootCommand.SetHandler (
                                 context =>
@@ -157,7 +164,8 @@ public class UICatalogApp
                                     var options = new Options
                                     {
                                         Driver = context.ParseResult.GetValueForOption (driverOption) ?? string.Empty,
-                                        Scenario = context.ParseResult.GetValueForArgument (scenarioArgument)
+                                        Benchmark = context.ParseResult.GetValueForOption (benchmarkFlag),
+                                        Scenario = context.ParseResult.GetValueForArgument (scenarioArgument),
                                         /* etc. */
                                     };
 
@@ -317,13 +325,28 @@ public class UICatalogApp
                                                                        )!);
             _selectedScenario = (Scenario)Activator.CreateInstance (_scenarios [item].GetType ())!;
 
-            BenchmarkScenario ();
+            var results = RunScenario (_selectedScenario, options.Benchmark);
+            if (results is { })
+            {
+                Console.WriteLine (JsonSerializer.Serialize (results, new JsonSerializerOptions ()
+                {
+                    WriteIndented = true
+                }));
+            }
 
             VerifyObjectsWereDisposed ();
 
             return;
         }
 
+        // Benchmark all Scenarios
+        if (options.Benchmark)
+        {
+            BenchmarkAllScenarios ();
+
+            return;
+        }
+
         while (RunUICatalogTopLevel () is { } scenario)
         {
             VerifyObjectsWereDisposed ();
@@ -369,145 +392,178 @@ public class UICatalogApp
         VerifyObjectsWereDisposed ();
 
         return;
-
-
     }
 
-    private static void BenchmarkScenario ()
+    private static BenchmarkResults? RunScenario (Scenario scenario, bool benchsmark)
     {
-        object _timeoutLock = new ();
-
-        uint maxIterations = 1000;
-        uint abortTime = 5000;
-        object timeout = null;
-        var initialized = false;
-        var shutdown = false;
+        if (benchsmark)
+        {
+            scenario.StartBenchmark ();
+        }
 
-        int iterationCount = 0;
-        int clearedContentCount = 0;
-        int refreshedCount = 0;
-        int updatedCount = 0;
-        int drawCompleteCount = 0;
+        Application.Init (driverName: _forceDriver);
+        scenario.TopLevelColorScheme = _topLevelColorScheme;
 
-        int laidOutCount = 0;
+        Application.Screen = new (0, 0,120, 50);
+        scenario.Main ();
 
-        Console.WriteLine ($"Scenario {_selectedScenario.GetName ()}");
+        BenchmarkResults? results = null;
 
-        Stopwatch stopwatch = null;
+        if (benchsmark)
+        {
+            results = scenario.EndBenchmark ();
+        }
 
-        Application.InitializedChanged += OnApplicationOnInitializedChanged;
+        scenario.Dispose ();
 
-        Application.Init (driverName: _forceDriver);
-        _selectedScenario.TopLevelColorScheme = _topLevelColorScheme;
-
-        _selectedScenario.Main ();
+        // TODO: Throw if shutdown was not called already
+        Application.Shutdown ();
 
-        Application.InitializedChanged -= OnApplicationOnInitializedChanged;
+        return results;
+    }
 
-        Console.WriteLine ($"  ran for {iterationCount} iterations.");
-        Console.WriteLine ($"  took {stopwatch?.ElapsedMilliseconds} ms to run.");
-        Console.WriteLine ($"  called Driver.ClearContents {clearedContentCount} times.");
-        Console.WriteLine ($"  called Driver.Refresh {refreshedCount} times.");
-        Console.WriteLine ($"    which updated the screen {updatedCount} times.");
-        Console.WriteLine ($"  called View.Draw {drawCompleteCount} times.");
-        Console.WriteLine ($"  called View.LayoutComplete {laidOutCount} times.");
 
-        _selectedScenario.Dispose ();
-        _selectedScenario = null;
+    private static void BenchmarkAllScenarios ()
+    {
+        List<BenchmarkResults> resultsList = new List<BenchmarkResults> ();
 
-        lock (_timeoutLock)
+        int maxScenarios = 5;
+        foreach (var s in _scenarios!)
         {
-            if (timeout is { })
+            resultsList.Add (RunScenario (s, true)!);
+            maxScenarios--;
+
+            if (maxScenarios == 0)
             {
-                timeout = null;
+                //break;
             }
         }
 
-        // TODO: Throw if shutdown was not called already
-        Application.Shutdown ();
-
-        return;
+        if (resultsList.Count > 0)
+        {
+            var output = JsonSerializer.Serialize (
+                                                   resultsList,
+                                                   new JsonSerializerOptions ()
+                                                   {
+                                                       WriteIndented = true
+                                                   });
+            Console.WriteLine (output);
 
+            Application.Init ();
 
-        void OnApplicationOnInitializedChanged (object s, EventArgs<bool> a)
-        {
-            if (a.CurrentValue)
+            var benchmarkWindow = new Window ()
             {
-                lock (_timeoutLock)
-                {
-                    timeout = Application.AddTimeout (TimeSpan.FromMilliseconds (abortTime), ForceCloseCallback);
-                }
+                Title = "Benchmark Results",
+            };
+            benchmarkWindow.Border.Thickness = new (0, 0, 0, 0);
 
-                initialized = true;
-                Application.Iteration += OnApplicationOnIteration;
-                Application.Driver!.ClearedContents += (sender, args) => clearedContentCount++;
-                Application.Driver!.Refreshed += (sender, args) =>
-                {
-                    refreshedCount++;
+            TableView resultsTableView = new ()
+            {
+                Width = Dim.Fill (),
+                Height = Dim.Fill (),
+            };
 
-                    if (args.CurrentValue)
-                    {
-                        updatedCount++;
-                    }
-                };
-                Application.NotifyNewRunState += OnApplicationNotifyNewRunState;
+            // TableView provides many options for table headers. For simplicity we turn all 
+            // of these off. By enabling FullRowSelect and turning off headers, TableView looks just
+            // like a ListView
+            resultsTableView.FullRowSelect = true;
+            resultsTableView.Style.ShowHeaders = true;
+            resultsTableView.Style.ShowHorizontalHeaderOverline = false;
+            resultsTableView.Style.ShowHorizontalHeaderUnderline = true;
+            resultsTableView.Style.ShowHorizontalBottomline = false;
+            resultsTableView.Style.ShowVerticalCellLines = true;
+            resultsTableView.Style.ShowVerticalHeaderLines = true;
 
-                stopwatch = Stopwatch.StartNew ();
-            }
-            else
-            {
-                shutdown = true;
-                Application.NotifyNewRunState -= OnApplicationNotifyNewRunState;
-                Application.Iteration -= OnApplicationOnIteration;
-                stopwatch?.Stop ();
-            }
-        }
+            /* By default TableView lays out columns at render time and only
+                 * measures y rows of data at a time.  Where y is the height of the
+                 * console. This is for the following reasons:
+                 *
+                 * - Performance, when tables have a large amount of data
+                 * - Defensive, prevents a single wide cell value pushing other
+                 *   columns off screen (requiring horizontal scrolling
+                 *
+                 * In the case of UICatalog here, such an approach is overkill so
+                 * we just measure all the data ourselves and set the appropriate
+                 * max widths as ColumnStyles
+                 */
+            //int longestName = _scenarios!.Max (s => s.GetName ().Length);
+
+            //resultsTableView.Style.ColumnStyles.Add (
+            //                                     0,
+            //                                     new () { MaxWidth = longestName, MinWidth = longestName, MinAcceptableWidth = longestName }
+            //                                    );
+            //resultsTableView.Style.ColumnStyles.Add (1, new () { MaxWidth = 1 });
+            //resultsTableView.CellActivated += ScenarioView_OpenSelectedItem;
 
-        void OnApplicationOnIteration (object s, IterationEventArgs a)
-        {
-            iterationCount++;
-            if (iterationCount > maxIterations)
-            {
-                Application.RequestStop ();
-            }
-        }
+            // TableView typically is a grid where nav keys are biased for moving left/right.
+            resultsTableView.KeyBindings.Remove (Key.Home);
+            resultsTableView.KeyBindings.Add (Key.Home, Command.Start);
+            resultsTableView.KeyBindings.Remove (Key.End);
+            resultsTableView.KeyBindings.Add (Key.End, Command.End);
 
+            // Ideally, TableView.MultiSelect = false would turn off any keybindings for
+            // multi-select options. But it currently does not. UI Catalog uses Ctrl-A for
+            // a shortcut to About.
+            resultsTableView.MultiSelect = false;
 
-        void OnApplicationNotifyNewRunState (object sender, RunStateEventArgs e)
-        {
-            // Get a list of all subviews under Application.Top (and their subviews, etc.)
-            // and subscribe to their DrawComplete event
-            void SubscribeAllSubviews (View view)
-            {
-                view.DrawComplete += (s, a) => drawCompleteCount++;
-                view.SubviewsLaidOut += (s, a) => laidOutCount++;
-                foreach (View subview in view.Subviews)
-                {
-                    SubscribeAllSubviews (subview);
-                }
-            }
+            var dt = new DataTable ();
 
-            SubscribeAllSubviews (Application.Top);
-        }
+            dt.Columns.Add (new DataColumn ("Scenario", typeof (string)));
+            dt.Columns.Add (new DataColumn ("Duration", typeof (TimeSpan)));
+            dt.Columns.Add (new DataColumn ("Refreshed", typeof (int)));
+            dt.Columns.Add (new DataColumn ("LaidOut", typeof (int)));
+            dt.Columns.Add (new DataColumn ("ClearedContent", typeof (int)));
+            dt.Columns.Add (new DataColumn ("DrawComplete", typeof (int)));
+            dt.Columns.Add (new DataColumn ("Updated", typeof (int)));
+            dt.Columns.Add (new DataColumn ("Iterations", typeof (int)));
 
-        // If the scenario doesn't close within the abort time, this will force it to quit
-        bool ForceCloseCallback ()
-        {
-            lock (_timeoutLock)
+            foreach (var r in resultsList)
             {
-                if (timeout is { })
-                {
-                    timeout = null;
-                }
+                dt.Rows.Add (
+                             r.Scenario,
+                             r.Duration,
+                             r.RefreshedCount,
+                             r.LaidOutCount,
+                             r.ClearedContentCount,
+                             r.DrawCompleteCount,
+                             r.UpdatedCount,
+                             r.IterationCount
+                            );
             }
 
-            Console.WriteLine ($"  Failed to Quit with {Application.QuitKey} after {abortTime}ms and {iterationCount} iterations. Force quit.");
-
-            Application.RequestStop ();
-
-            return false;
+            BenchmarkResults totalRow = new ()
+            {
+                Scenario = "TOTAL",
+                Duration = new TimeSpan (resultsList.Sum (r => r.Duration.Ticks)),
+                RefreshedCount = resultsList.Sum (r => r.RefreshedCount),
+                LaidOutCount = resultsList.Sum (r => r.LaidOutCount),
+                ClearedContentCount = resultsList.Sum (r => r.ClearedContentCount),
+                DrawCompleteCount = resultsList.Sum (r => r.DrawCompleteCount),
+                UpdatedCount = resultsList.Sum (r => r.UpdatedCount),
+                IterationCount = resultsList.Sum (r => r.IterationCount),
+            };
+            dt.Rows.Add(
+                        totalRow.Scenario,
+                        totalRow.Duration,
+                        totalRow.RefreshedCount,
+                        totalRow.LaidOutCount,
+                        totalRow.ClearedContentCount,
+                        totalRow.DrawCompleteCount,
+                        totalRow.UpdatedCount,
+                        totalRow.IterationCount
+                       );
+
+            dt.DefaultView.Sort = "Duration";
+            DataTable sortedCopy = dt.DefaultView.ToTable ();
+
+            resultsTableView.Table = new DataTableSource (sortedCopy);
+
+            benchmarkWindow.Add (resultsTableView);
+
+            Application.Run (benchmarkWindow);
+            benchmarkWindow.Dispose ();
+            Application.Shutdown ();
         }
-
     }
 
     private static void VerifyObjectsWereDisposed ()
@@ -695,7 +751,7 @@ public class UICatalogApp
                                              {
                                                  if (_statusBar.NeedsLayout)
                                                  {
-                                                    throw new LayoutException ("DimFunc.Fn aborted because dependent View needs layout.");
+                                                     throw new LayoutException ("DimFunc.Fn aborted because dependent View needs layout.");
                                                  }
                                                  return _statusBar.Frame.Height;
                                              })),
@@ -1263,6 +1319,8 @@ public class UICatalogApp
         public string Driver;
 
         public string Scenario;
+
+        public bool Benchmark;
         /* etc. */
     }
 }