浏览代码

Fixes #2485 ++ - Wizard v2 architecture modernization with Padding-based layout (#4510)

* Initial plan

* Fix Wizard v2 architecture issues - ScrollBar API, event handlers, key bindings

Co-authored-by: tig <[email protected]>

* Implement issue #4155 - Put nav buttons in bottom Padding, Help in right Padding

Co-authored-by: tig <[email protected]>

* Address code review feedback - Extract helper method, improve null checks

Co-authored-by: tig <[email protected]>

* Fix disposal issue - Ensure _helpTextView is always disposed

Co-authored-by: tig <[email protected]>

* Refactor & improvements. WIP

* Tweaking layout

* Wizard tweaks

* Added View.GetSubViews that optinoally gets subviews of adornments

* Refactor Wizard API: modern events, layout, and design

- Replaced custom event args with standard .NET event args (CancelEventArgs, ValueChangingEventArgs, etc.)
- Removed Finished event; use Accepting for wizard completion
- Updated Cancelled, MovingBack, MovingNext to use CancelEventArgs
- Refactored UICatalog scenarios and tests to new event model
- Improved WizardStep sizing and wizard auto-resizing to content
- Enhanced IDesignable for Wizard and WizardStep with richer design-time UI
- Simplified help text padding logic in WizardStep
- Removed obsolete code and modernized code style throughout
- Improves API consistency, usability, and .NET idiomatic usage

* Fixes #4515 - Navigating into and out of Adornments does not work

* WIP. QUite broken.

* All fixed?

* Tweaks.

* Exclude Margin subviews from drawing; add shadow tests

Update Margin adornment to skip drawing subviews that are themselves Margin views, preventing unsupported nested Margin rendering. Add unit tests to verify that opaque-shadowed buttons in Margin are not drawn, while Border and Padding still support shadow rendering. Update test class to use output helper and assert driver output.

* Final code cleanup and test improvements.

* Update Margin.cs

Co-authored-by: Copilot <[email protected]>

* Update View.cs

Co-authored-by: Copilot <[email protected]>

* Update View.Hierarchy.cs

Co-authored-by: Copilot <[email protected]>

* Update View.Hierarchy.cs

Co-authored-by: Copilot <[email protected]>

* Refactor: code style, formatting, and minor logic cleanup

- Standardized spacing and formatting for method signatures and object initializations.
- Converted simple methods and properties to expression-bodied members for conciseness.
- Replaced named arguments with positional arguments for consistency.
- Improved XML documentation formatting for readability.
- Simplified logic in event handlers (e.g., Wizard Back button).
- Removed redundant checks where properties are guaranteed to exist.
- Fixed minor bugs related to padding, height calculation, and event handling.
- Adopted consistent use of `var` for local variables.
- Corrected namespace declarations.
- Refactored methods returning constants to use expression-bodied syntax.
- General code cleanup for clarity and maintainability; no breaking changes.

* api docs

---------

Co-authored-by: copilot-swe-agent[bot] <[email protected]>
Co-authored-by: tig <[email protected]>
Co-authored-by: Tig <[email protected]>
Co-authored-by: Copilot <[email protected]>
Copilot 2 天之前
父节点
当前提交
4145b984ba
共有 29 个文件被更改,包括 3481 次插入1354 次删除
  1. 56 49
      Examples/UICatalog/Scenarios/Adornments.cs
  2. 0 158
      Examples/UICatalog/Scenarios/WizardAsView.cs
  3. 123 330
      Examples/UICatalog/Scenarios/Wizards.cs
  4. 2 1
      Examples/UICatalog/UICatalog.cs
  5. 4 31
      Terminal.Gui/ViewBase/Adornment/Adornment.cs
  6. 8 5
      Terminal.Gui/ViewBase/Adornment/Border.Arrangment.cs
  7. 28 17
      Terminal.Gui/ViewBase/Adornment/Margin.cs
  8. 56 11
      Terminal.Gui/ViewBase/Adornment/Padding.cs
  9. 3 4
      Terminal.Gui/ViewBase/View.Adornments.cs
  10. 52 36
      Terminal.Gui/ViewBase/View.Drawing.cs
  11. 81 7
      Terminal.Gui/ViewBase/View.Hierarchy.cs
  12. 17 26
      Terminal.Gui/ViewBase/View.Navigation.cs
  13. 2 2
      Terminal.Gui/ViewBase/View.ScrollBars.cs
  14. 27 23
      Terminal.Gui/ViewBase/View.cs
  15. 4 0
      Terminal.Gui/Views/TextInput/TextView.cs
  16. 268 352
      Terminal.Gui/Views/Wizard/Wizard.cs
  17. 0 35
      Terminal.Gui/Views/Wizard/WizardEventArgs.cs
  18. 104 141
      Terminal.Gui/Views/Wizard/WizardStep.cs
  19. 4 1
      Terminal.sln.DotSettings
  20. 4 4
      Tests/UnitTests/Dialogs/WizardTests.cs
  21. 97 14
      Tests/UnitTestsParallelizable/ViewBase/Adornment/AdornmentSubViewTests.cs
  22. 25 0
      Tests/UnitTestsParallelizable/ViewBase/Adornment/PaddingTests.cs
  23. 0 2
      Tests/UnitTestsParallelizable/ViewBase/Layout/GetViewsUnderLocationForRootTests.cs
  24. 586 0
      Tests/UnitTestsParallelizable/ViewBase/Navigation/AdornmentNavigationTests.cs
  25. 11 1
      Tests/UnitTestsParallelizable/ViewBase/Navigation/AllViewsNavigationTests.cs
  26. 420 103
      Tests/UnitTestsParallelizable/ViewBase/SubviewTests.cs
  27. 1 1
      Tests/UnitTestsParallelizable/Views/TextViewTests.cs
  28. 479 0
      Tests/UnitTestsParallelizable/Views/WizardStepTests.cs
  29. 1019 0
      Tests/UnitTestsParallelizable/Views/WizardTests.cs

+ 56 - 49
Examples/UICatalog/Scenarios/Adornments.cs

@@ -1,4 +1,7 @@
-using System;
+#nullable enable
+// ReSharper disable AccessToDisposedClosure
+
+// ReSharper disable AssignNullToNotNullAttribute
 
 namespace UICatalog.Scenarios;
 
@@ -10,12 +13,11 @@ public class Adornments : Scenario
     public override void Main ()
     {
         Application.Init ();
+        using IApplication app = Application.Instance;
 
-        Window appWindow = new ()
-        {
-            Title = GetQuitKeyAndName (),
-            BorderStyle = LineStyle.None
-        };
+        using Window appWindow = new ();
+        appWindow.Title = GetQuitKeyAndName ();
+        appWindow.BorderStyle = LineStyle.None;
 
         var editor = new AdornmentsEditor
         {
@@ -31,7 +33,7 @@ public class Adornments : Scenario
 
         appWindow.Add (editor);
 
-        var window = new Window
+        Window window = new ()
         {
             Title = "The _Window",
             Arrangement = ViewArrangement.Overlapped | ViewArrangement.Movable,
@@ -41,29 +43,29 @@ public class Adornments : Scenario
         };
         appWindow.Add (window);
 
-        var tf1 = new TextField { Width = 10, Text = "TextField" };
-        var color = new ColorPicker16 { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd () };
+        TextField tf1 = new () { Width = 10, Text = "TextField" };
+        ColorPicker16 color = new () { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd () };
         color.BorderStyle = LineStyle.RoundedDotted;
 
-        color.ColorChanged += (s, e) =>
+        color.ColorChanged += (_, e) =>
                               {
                                   color.SuperView!.SetScheme (
-                                                             new (color.SuperView.GetScheme ())
-                                                             {
-                                                                 Normal = new (
-                                                                               color.SuperView.GetAttributeForRole (VisualRole.Normal).Foreground,
-                                                                               e.Result,
-                                                                               color.SuperView.GetAttributeForRole (VisualRole.Normal).Style
-                                                                              )
-                                                             });
+                                                              new (color.SuperView.GetScheme ())
+                                                              {
+                                                                  Normal = new (
+                                                                                color.SuperView.GetAttributeForRole (VisualRole.Normal).Foreground,
+                                                                                e.Result,
+                                                                                color.SuperView.GetAttributeForRole (VisualRole.Normal).Style
+                                                                               )
+                                                              });
                               };
 
-        var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
+        Button button = new () { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
 
-        button.Accepting += (s, e) =>
-                             MessageBox.Query (appWindow.App, 20, 7, "Hi", $"Am I a {window.GetType ().Name}?", "Yes", "No");
+        button.Accepting += (_, _) =>
+                                MessageBox.Query (appWindow.App!, 20, 7, "Hi", $"Am I a {window.GetType ().Name}?", "Yes", "No");
 
-        var label = new TextView
+        TextView label = new ()
         {
             X = Pos.Center (),
             Y = Pos.Bottom (button),
@@ -74,9 +76,9 @@ public class Adornments : Scenario
         };
         label.Border!.Thickness = new (1, 3, 1, 1);
 
-        var btnButtonInWindow = new Button { X = Pos.AnchorEnd (), Y = Pos.AnchorEnd (), Text = "Button" };
+        Button btnButtonInWindow = new () { X = Pos.AnchorEnd (), Y = Pos.AnchorEnd (), Text = "Button" };
 
-        var labelAnchorEnd = new Label
+        Label labelAnchorEnd = new ()
         {
             Y = Pos.AnchorEnd (),
             Width = 40,
@@ -87,68 +89,76 @@ public class Adornments : Scenario
 
         window.Margin!.Data = "Margin";
         window.Margin!.Text = "Margin Text";
-        window.Margin!.Thickness = new (0);
+        window.Margin!.Thickness = new (3);
 
         window.Border!.Data = "Border";
         window.Border!.Text = "Border Text";
-        window.Border!.Thickness = new (0);
+        window.Border!.Thickness = new (5);
+        window.Border!.SetScheme (SchemeManager.GetScheme (Schemes.Dialog));
 
-        window.Padding.Data = "Padding";
+        window.Padding!.Data = "Padding";
         window.Padding.Text = "Padding Text line 1\nPadding Text line 3\nPadding Text line 3\nPadding Text line 4\nPadding Text line 5";
-        window.Padding.Thickness = new (3);
-        window.Padding.SchemeName = "Error";
+        window.Padding.Thickness = new (4);
+        window.Padding!.SetScheme (SchemeManager.GetScheme (Schemes.Menu));
         window.Padding.CanFocus = true;
 
-        var longLabel = new Label
+        Label longLabel = new ()
         {
             X = 40, Y = 5, Title = "This is long text (in a label) that should clip."
         };
         longLabel.TextFormatter.WordWrap = true;
         window.Add (tf1, color, button, label, btnButtonInWindow, labelAnchorEnd, longLabel);
 
-        window.Initialized += (s, e) =>
+        window.Initialized += (_, _) =>
                               {
                                   editor.ViewToEdit = window;
 
                                   editor.ShowViewIdentifier = true;
 
-                                  var labelInPadding = new Label { X = 0, Y = 1, Title = "_Text:" };
+                                  // NOTE: Adding SubViews to Margin is not supported
+
+                                  Button btnButtonInBorder = new ()
+                                  {
+                                      X = Pos.Center (),
+                                      Y = 1,
+                                      Text = "_Button in Border Y = 1"
+                                  };
+                                  btnButtonInBorder.Accepting += (_, _) => MessageBox.Query (appWindow.App!, 20, 7, "Hi", "Button in Border Pressed!", "Ok");
+                                  window.Border.Add (btnButtonInBorder);
+
+                                  Label labelInPadding = new () { X = 0, Y = 1, Title = "_Text:" };
                                   window.Padding.Add (labelInPadding);
 
-                                  var textFieldInPadding = new TextField
+                                  TextField textFieldInPadding = new ()
                                   {
                                       X = Pos.Right (labelInPadding) + 1,
                                       Y = Pos.Top (labelInPadding), Width = 10,
-                                      Text = "text (Y = 1)",
-                                      CanFocus = true
+                                      Text = "text (Y = 1)"
                                   };
-                                  textFieldInPadding.Accepting += (s, e) => MessageBox.Query (appWindow.App, 20, 7, "TextField", textFieldInPadding.Text, "Ok");
+
+                                  textFieldInPadding.Accepting += (_, _) => MessageBox.Query (appWindow.App!, 20, 7, "TextField", textFieldInPadding.Text, "Ok");
                                   window.Padding.Add (textFieldInPadding);
 
-                                  var btnButtonInPadding = new Button
+                                  Button btnButtonInPadding = new ()
                                   {
                                       X = Pos.Center (),
                                       Y = 1,
-                                      Text = "_Button in Padding Y = 1",
-                                      CanFocus = true,
-                                      HighlightStates = MouseState.None,
+                                      Text = "_Button in Padding Y = 1"
                                   };
-                                  btnButtonInPadding.Accepting += (s, e) => MessageBox.Query (appWindow.App, 20, 7, "Hi", "Button in Padding Pressed!", "Ok");
-                                  btnButtonInPadding.BorderStyle = LineStyle.Dashed;
-                                  btnButtonInPadding.Border!.Thickness = new (1, 1, 1, 1);
+                                  btnButtonInPadding.Accepting += (_, _) => MessageBox.Query (appWindow.App!, 20, 7, "Hi", "Button in Padding Pressed!", "Ok");
                                   window.Padding.Add (btnButtonInPadding);
 
 #if SUBVIEW_BASED_BORDER
                                 btnButtonInPadding.Border!.CloseButton.Visible = true;
 
                                 view.Border!.CloseButton.Visible = true;
-                                view.Border!.CloseButton.Accept += (s, e) =>
+                                view.Border!.CloseButton.Accept += (_, _) =>
                                                                   {
                                                                       MessageBox.Query (20, 7, "Hi", "Window Close Button Pressed!", "Ok");
                                                                       e.Handled = true;
                                                                   };
 
-                                view.Accept += (s, e) => MessageBox.Query (20, 7, "Hi", "Window Close Button Pressed!", "Ok");
+                                view.Accept += (_, _) => MessageBox.Query (20, 7, "Hi", "Window Close Button Pressed!", "Ok");
 #endif
                               };
 
@@ -156,9 +166,6 @@ public class Adornments : Scenario
         editor.AutoSelectSuperView = window;
         editor.AutoSelectAdornments = true;
 
-        Application.Run (appWindow);
-        appWindow.Dispose ();
-
-        Application.Shutdown ();
+        app.Run (appWindow);
     }
 }

+ 0 - 158
Examples/UICatalog/Scenarios/WizardAsView.cs

@@ -1,158 +0,0 @@
-#nullable enable
-
-namespace UICatalog.Scenarios;
-
-[ScenarioMetadata ("WizardAsView", "Shows using the Wizard class in an non-modal way")]
-[ScenarioCategory ("Wizards")]
-public class WizardAsView : Scenario
-{
-    public override void Main ()
-    {
-        Application.Init ();
-
-        // MenuBar
-        MenuBar menu = new ();
-
-        menu.Add (
-                  new MenuBarItem (
-                                   "_File",
-                                   [
-                                       new MenuItem
-                                       {
-                                           Title = "_Restart Configuration...",
-                                           Action = () => MessageBox.Query (
-                                                                            Application.Instance,
-                                                                            "Wizard",
-                                                                            "Are you sure you want to reset the Wizard and start over?",
-                                                                            "Ok",
-                                                                            "Cancel"
-                                                                           )
-                                       },
-                                       new MenuItem
-                                       {
-                                           Title = "Re_boot Server...",
-                                           Action = () => MessageBox.Query (
-                                                                            Application.Instance,
-                                                                            "Wizard",
-                                                                            "Are you sure you want to reboot the server start over?",
-                                                                            "Ok",
-                                                                            "Cancel"
-                                                                           )
-                                       },
-                                       new MenuItem
-                                       {
-                                           Title = "_Shutdown Server...",
-                                           Action = () => MessageBox.Query (
-                                                                            Application.Instance,
-                                                                            "Wizard",
-                                                                            "Are you sure you want to cancel setup and shutdown?",
-                                                                            "Ok",
-                                                                            "Cancel"
-                                                                           )
-                                       }
-                                   ]
-                                  )
-                 );
-
-        // No need for a Title because the border is disabled
-        Wizard wizard = new ()
-        {
-            X = 0,
-            Y = Pos.Bottom (menu),
-            Width = Dim.Fill (),
-            Height = Dim.Fill (),
-            ShadowStyle = ShadowStyle.None
-        };
-
-        // Set Modal to false to cause the Wizard class to render without a frame and
-        // behave like an non-modal View (vs. a modal/pop-up Window).
-       // wizard.Modal = false;
-
-        wizard.MovingBack += (s, args) =>
-                             {
-                                 //args.Cancel = true;
-                                 //actionLabel.Text = "Moving Back";
-                             };
-
-        wizard.MovingNext += (s, args) =>
-                             {
-                                 //args.Cancel = true;
-                                 //actionLabel.Text = "Moving Next";
-                             };
-
-        wizard.Finished += (s, args) =>
-                           {
-                               //args.Cancel = true;
-                               MessageBox.Query ((s as View)?.App!, "Setup Wizard", "Finished", "Ok");
-                               Application.RequestStop ();
-                           };
-
-        wizard.Cancelled += (s, args) =>
-                            {
-                                int? btn = MessageBox.Query ((s as View)?.App!, "Setup Wizard", "Are you sure you want to cancel?", "Yes", "No");
-                                args.Cancel = btn == 1;
-
-                                if (btn == 0)
-                                {
-                                    Application.RequestStop ();
-                                }
-                            };
-
-        // Add 1st step
-        WizardStep firstStep = new () { Title = "End User License Agreement" };
-        wizard.AddStep (firstStep);
-        firstStep.NextButtonText = "Accept!";
-
-        firstStep.HelpText =
-            "This is the End User License Agreement.\n\n\n\n\n\nThis is a test of the emergency broadcast system. This is a test of the emergency broadcast system.\nThis is a test of the emergency broadcast system.\n\n\nThis is a test of the emergency broadcast system.\n\nThis is a test of the emergency broadcast system.\n\n\n\nThe end of the EULA.";
-
-        // Add 2nd step
-        WizardStep secondStep = new () { Title = "Second Step" };
-        wizard.AddStep (secondStep);
-
-        secondStep.HelpText =
-            "This is the help text for the Second Step.\n\nPress the button to change the Title.\n\nIf First Name is empty the step will prevent moving to the next step.";
-
-        Label buttonLbl = new () { Text = "Second Step Button: ", X = 0, Y = 0 };
-
-        Button button = new ()
-        {
-            Text = "Press Me to Rename Step",
-            X = Pos.Right (buttonLbl),
-            Y = Pos.Top (buttonLbl)
-        };
-
-        button.Accepting += (s, e) =>
-                            {
-                                secondStep.Title = "2nd Step";
-
-                                MessageBox.Query ((s as View)?.App!,
-                                                  "Wizard Scenario",
-                                                  "This Wizard Step's title was changed to '2nd Step'",
-                                                  "Ok"
-                                                 );
-                            };
-        secondStep.Add (buttonLbl, button);
-
-        Label lbl = new () { Text = "First Name: ", X = Pos.Left (buttonLbl), Y = Pos.Bottom (buttonLbl) };
-        TextField firstNameField = new () { Text = "Number", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
-        secondStep.Add (lbl, firstNameField);
-        lbl = new () { Text = "Last Name:  ", X = Pos.Left (buttonLbl), Y = Pos.Bottom (lbl) };
-        TextField lastNameField = new () { Text = "Six", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
-        secondStep.Add (lbl, lastNameField);
-
-        // Add last step
-        WizardStep lastStep = new () { Title = "The last step" };
-        wizard.AddStep (lastStep);
-
-        lastStep.HelpText =
-            "The wizard is complete!\n\nPress the Finish button to continue.\n\nPressing Esc will cancel.";
-
-        Window window = new ();
-        window.Add (menu, wizard);
-
-        Application.Run (window);
-        window.Dispose ();
-        Application.Shutdown ();
-    }
-}

+ 123 - 330
Examples/UICatalog/Scenarios/Wizards.cs

@@ -1,4 +1,9 @@
-namespace UICatalog.Scenarios;
+#nullable enable
+
+// ReSharper disable AccessToDisposedClosure
+using Terminal.Gui.Views;
+
+namespace UICatalog.Scenarios;
 
 [ScenarioMetadata ("Wizards", "Demonstrates the Wizard class")]
 [ScenarioCategory ("Dialogs")]
@@ -6,85 +11,64 @@
 [ScenarioCategory ("Runnable")]
 public class Wizards : Scenario
 {
+    private Wizard? _wizard;
+    private View? _actionLabel;
+    private TextField? _titleEdit;
+
     public override void Main ()
     {
         Application.Init ();
-        var win = new Window { Title = GetQuitKeyAndName () };
+        using IApplication app = Application.Instance;
 
-        var frame = new FrameView
+        using Window win = new ();
+        win.Title = GetQuitKeyAndName ();
+
+        FrameView settingsFrame = new ()
         {
             X = Pos.Center (),
             Y = 0,
             Width = Dim.Percent (75),
-            SchemeName = "Base",
+            Height = Dim.Auto (),
             Title = "Wizard Options"
         };
-        win.Add (frame);
-
-        var label = new Label { X = 0, Y = 0, TextAlignment = Alignment.End, Text = "_Width:", Width = 10 };
-        frame.Add (label);
-
-        var widthEdit = new TextField
-        {
-            X = Pos.Right (label) + 1,
-            Y = Pos.Top (label),
-            Width = 5,
-            Height = 1,
-            Text = "80"
-        };
-        frame.Add (widthEdit);
+        win.Add (settingsFrame);
 
-        label = new ()
+        Label label = new ()
         {
             X = 0,
-            Y = Pos.Bottom (label),
-
-            Width = Dim.Width (label),
-            Height = 1,
             TextAlignment = Alignment.End,
-            Text = "_Height:"
+            Text = "_Title:"
         };
-        frame.Add (label);
+        settingsFrame.Add (label);
 
-        var heightEdit = new TextField
+        _titleEdit = new ()
         {
             X = Pos.Right (label) + 1,
             Y = Pos.Top (label),
-            Width = 5,
+            Width = Dim.Fill (),
             Height = 1,
-            Text = "20"
+            Text = "Gandolf"
         };
-        frame.Add (heightEdit);
+        settingsFrame.Add (_titleEdit);
 
-        label = new ()
+        CheckBox cbRun = new ()
         {
+            Title = "_Run Wizard as a modal",
             X = 0,
             Y = Pos.Bottom (label),
-
-            Width = Dim.Width (label),
-            Height = 1,
-            TextAlignment = Alignment.End,
-            Text = "_Title:"
+            CheckedState = CheckState.Checked
         };
-        frame.Add (label);
+        settingsFrame.Add (cbRun);
 
-        var titleEdit = new TextField
+        Button showWizardButton = new ()
         {
-            X = Pos.Right (label) + 1,
-            Y = Pos.Top (label),
-            Width = Dim.Fill (),
-            Height = 1,
-            Text = "Gandolf"
+            X = Pos.Center (),
+            Y = Pos.Bottom (cbRun),
+            IsDefault = true,
+            Text = "_Show Wizard"
         };
-        frame.Add (titleEdit);
 
-        void Win_Loaded (object sender, EventArgs args)
-        {
-            frame.Height = widthEdit.Frame.Height + heightEdit.Frame.Height + titleEdit.Frame.Height + 2;
-            win.IsModalChanged -= Win_Loaded;
-        }
-
-        win.IsModalChanged += Win_Loaded;
+        settingsFrame.Add (showWizardButton);
 
         label = new ()
         {
@@ -92,295 +76,104 @@ public class Wizards : Scenario
         };
         win.Add (label);
 
-        var actionLabel = new Label
+        _actionLabel = new ()
         {
-            X = Pos.Right (label), Y = Pos.AnchorEnd (1), SchemeName = "Error"
+            X = Pos.Right (label),
+            Y = Pos.AnchorEnd (1),
+            SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Error),
+            Width = Dim.Auto (),
+            Height = Dim.Auto ()
         };
-        win.Add (actionLabel);
+        win.Add (_actionLabel);
 
-        var showWizardButton = new Button
+        if (cbRun.CheckedState != CheckState.Checked)
         {
-            X = Pos.Center (), Y = Pos.Bottom (frame) + 2, IsDefault = true, Text = "_Show Wizard"
-        };
-
-        showWizardButton.Accepting += (s, e) =>
-                                      {
-                                          try
-                                          {
-                                              var width = 0;
-                                              int.TryParse (widthEdit.Text, out width);
-                                              var height = 0;
-                                              int.TryParse (heightEdit.Text, out height);
-
-                                              if (width < 1 || height < 1)
-                                              {
-                                                  MessageBox.ErrorQuery (
-                                                                         (s as View)?.App,
-                                                                         "Nope",
-                                                                         "Height and width must be greater than 0 (much bigger)",
-                                                                         "Ok"
-                                                                        );
-
-                                                  return;
-                                              }
-
-                                              actionLabel.Text = string.Empty;
-
-                                              var wizard = new Wizard { Title = titleEdit.Text, Width = width, Height = height };
-
-                                              wizard.MovingBack += (s, args) =>
-                                                                   {
-                                                                       //args.Cancel = true;
-                                                                       actionLabel.Text = "Moving Back";
-                                                                   };
-
-                                              wizard.MovingNext += (s, args) =>
-                                                                   {
-                                                                       //args.Cancel = true;
-                                                                       actionLabel.Text = "Moving Next";
-                                                                   };
-
-                                              wizard.Finished += (s, args) =>
-                                                                 {
-                                                                     //args.Cancel = true;
-                                                                     actionLabel.Text = "Finished";
-                                                                 };
-
-                                              wizard.Cancelled += (s, args) =>
-                                                                  {
-                                                                      //args.Cancel = true;
-                                                                      actionLabel.Text = "Cancelled";
-                                                                  };
-
-                                              // Add 1st step
-                                              var firstStep = new WizardStep { Title = "End User License Agreement" };
-                                              firstStep.NextButtonText = "Accept!";
-
-                                              firstStep.HelpText =
-                                                  "This is the End User License Agreement.\n\n\n\n\n\nThis is a test of the emergency broadcast system. This is a test of the emergency broadcast system.\nThis is a test of the emergency broadcast system.\n\n\nThis is a test of the emergency broadcast system.\n\nThis is a test of the emergency broadcast system.\n\n\n\nThe end of the EULA.";
-
-                                              OptionSelector optionSelector = new ()
-                                              {
-                                                  Labels = ["_One", "_Two", "_3"]
-                                              };
-                                              firstStep.Add (optionSelector);
-
-                                              wizard.AddStep (firstStep);
-
-                                              // Add 2nd step
-                                              var secondStep = new WizardStep { Title = "Second Step" };
-                                              wizard.AddStep (secondStep);
-
-                                              secondStep.HelpText =
-                                                  "This is the help text for the Second Step.\n\nPress the button to change the Title.\n\nIf First Name is empty the step will prevent moving to the next step.";
-
-                                              var buttonLbl = new Label { Text = "Second Step Button: ", X = 1, Y = 1 };
-
-                                              var button = new Button
-                                              {
-                                                  Text = "Press Me to Rename Step", X = Pos.Right (buttonLbl), Y = Pos.Top (buttonLbl)
-                                              };
-
-                                              OptionSelector optionSelecor2 = new ()
-                                              {
-                                                  Labels = ["_A", "_B", "_C"],
-                                                  Orientation = Orientation.Horizontal
-                                              };
-                                              secondStep.Add (optionSelecor2);
-
-                                              button.Accepting += (s, e) =>
-                                                                  {
-                                                                      secondStep.Title = "2nd Step";
-
-                                                                      MessageBox.Query (
-                                                                                        (s as View)?.App,
-                                                                                        "Wizard Scenario",
-                                                                                        "This Wizard Step's title was changed to '2nd Step'"
-                                                                                       );
-                                                                  };
-                                              secondStep.Add (buttonLbl, button);
-                                              var lbl = new Label { Text = "First Name: ", X = 1, Y = Pos.Bottom (buttonLbl) };
-
-                                              var firstNameField =
-                                                  new TextField { Text = "Number", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
-                                              secondStep.Add (lbl, firstNameField);
-                                              lbl = new () { Text = "Last Name:  ", X = 1, Y = Pos.Bottom (lbl) };
-                                              var lastNameField = new TextField { Text = "Six", Width = 30, X = Pos.Right (lbl), Y = Pos.Top (lbl) };
-                                              secondStep.Add (lbl, lastNameField);
-
-                                              var thirdStepEnabledCeckBox = new CheckBox
-                                              {
-                                                  Text = "Enable Step _3",
-                                                  CheckedState = CheckState.UnChecked,
-                                                  X = Pos.Left (lastNameField),
-                                                  Y = Pos.Bottom (lastNameField)
-                                              };
-                                              secondStep.Add (thirdStepEnabledCeckBox);
-
-                                              // Add a frame 
-                                              var frame = new FrameView
-                                              {
-                                                  X = 0,
-                                                  Y = Pos.Bottom (thirdStepEnabledCeckBox) + 2,
-                                                  Width = Dim.Fill (),
-                                                  Height = 4,
-                                                  Title = "A Broken Frame (by Depeche Mode)",
-                                                  TabStop = TabBehavior.NoStop
-                                              };
-                                              frame.Add (new TextField { Text = "This is a TextField inside of the frame." });
-                                              secondStep.Add (frame);
-
-                                              wizard.StepChanging += (s, args) =>
-                                                                     {
-                                                                         if (args.OldStep == secondStep && string.IsNullOrEmpty (firstNameField.Text))
-                                                                         {
-                                                                             args.Cancel = true;
-
-                                                                             int? btn = MessageBox.ErrorQuery (
-                                                                                  (s as View)?.App,
-                                                                                  "Second Step",
-                                                                                  "You must enter a First Name to continue",
-                                                                                  "Ok"
-                                                                                 );
-                                                                         }
-                                                                     };
-
-                                              // Add 3rd (optional) step
-                                              var thirdStep = new WizardStep { Title = "Third Step (Optional)" };
-                                              wizard.AddStep (thirdStep);
-
-                                              thirdStep.HelpText =
-                                                  "This is step is optional (WizardStep.Enabled = false). Enable it with the checkbox in Step 2.";
-                                              var step3Label = new Label { Text = "This step is optional.", X = 0, Y = 0 };
-                                              thirdStep.Add (step3Label);
-                                              var progLbl = new Label { Text = "Third Step ProgressBar: ", X = 1, Y = 10 };
-
-                                              var progressBar = new ProgressBar
-                                              {
-                                                  X = Pos.Right (progLbl), Y = Pos.Top (progLbl), Width = 40, Fraction = 0.42F
-                                              };
-                                              thirdStep.Add (progLbl, progressBar);
-                                              thirdStep.Enabled = thirdStepEnabledCeckBox.CheckedState == CheckState.Checked;
-
-                                              thirdStepEnabledCeckBox.CheckedStateChanged += (s, e) =>
-                                                                                             {
-                                                                                                 thirdStep.Enabled =
-                                                                                                     thirdStepEnabledCeckBox.CheckedState == CheckState.Checked;
-                                                                                             };
-
-                                              // Add 4th step
-                                              var fourthStep = new WizardStep { Title = "Step Four" };
-                                              wizard.AddStep (fourthStep);
-
-                                              var someText = new TextView
-                                              {
-                                                  Text =
-                                                      "This step (Step Four) shows how to show/hide the Help pane. The step contains this TextView (but it's hard to tell it's a TextView because of Issue #1800).",
-                                                  X = 0,
-                                                  Y = 0,
-                                                  Width = Dim.Fill (),
-                                                  WordWrap = true,
-                                                  AllowsTab = false,
-                                                  SchemeName = "Base"
-                                              };
-
-                                              someText.Height = Dim.Fill (
-                                                                          Dim.Func (v => someText.SuperView is { IsInitialized: true }
-                                                                                             ? someText.SuperView.SubViews
-                                                                                                       .First (view => view.Y.Has<PosAnchorEnd> (out _))
-                                                                                                       .Frame.Height
-                                                                                             : 1));
-                                              var help = "This is helpful.";
-                                              fourthStep.Add (someText);
-
-                                              var hideHelpBtn = new Button
-                                              {
-                                                  Text = "Press me to show/hide help",
-                                                  X = Pos.Center (),
-                                                  Y = Pos.AnchorEnd ()
-                                              };
-
-                                              hideHelpBtn.Accepting += (s, e) =>
-                                                                       {
-                                                                           if (fourthStep.HelpText.Length > 0)
-                                                                           {
-                                                                               fourthStep.HelpText = string.Empty;
-                                                                           }
-                                                                           else
-                                                                           {
-                                                                               fourthStep.HelpText = help;
-                                                                           }
-                                                                       };
-                                              fourthStep.Add (hideHelpBtn);
-                                              fourthStep.NextButtonText = "_Go To Last Step";
-
-                                              //var scrollBar = new ScrollBarView (someText, true);
-
-                                              //scrollBar.ChangedPosition += (s, e) =>
-                                              //                             {
-                                              //                                 someText.TopRow = scrollBar.Position;
-
-                                              //                                 if (someText.TopRow != scrollBar.Position)
-                                              //                                 {
-                                              //                                     scrollBar.Position = someText.TopRow;
-                                              //                                 }
-
-                                              //                                 someText.SetNeedsDraw ();
-                                              //                             };
-
-                                              //someText.DrawingContent += (s, e) =>
-                                              //                        {
-                                              //                            scrollBar.Size = someText.Lines;
-                                              //                            scrollBar.Position = someText.TopRow;
-
-                                              //                            if (scrollBar.OtherScrollBarView != null)
-                                              //                            {
-                                              //                                scrollBar.OtherScrollBarView.Size = someText.Maxlength;
-                                              //                                scrollBar.OtherScrollBarView.Position = someText.LeftColumn;
-                                              //                            }
-                                              //                        };
-                                              //fourthStep.Add (scrollBar);
-
-                                              // Add last step
-                                              var lastStep = new WizardStep { Title = "The last step" };
-                                              wizard.AddStep (lastStep);
-
-                                              lastStep.HelpText =
-                                                  "The wizard is complete!\n\nPress the Finish button to continue.\n\nPressing ESC will cancel the wizard.";
+            showWizardButton.Enabled = false;
+            _wizard = CreateWizard ();
+            win.Add (_wizard);
+        }
 
-                                              var finalFinalStepEnabledCeckBox =
-                                                  new CheckBox { Text = "Enable _Final Final Step", CheckedState = CheckState.UnChecked, X = 0, Y = 1 };
-                                              lastStep.Add (finalFinalStepEnabledCeckBox);
+        cbRun.CheckedStateChanged += (_, a) =>
+        {
+            if (a.Value == CheckState.Checked)
+            {
+                showWizardButton.Enabled = true;
+                _wizard!.X = Pos.Center ();
+                _wizard.Y = Pos.Center ();
+
+                win.Remove (_wizard);
+                _wizard.Dispose ();
+                _wizard = null;
+            }
+            else
+            {
+                showWizardButton.Enabled = false;
+                _wizard = CreateWizard ();
+                _wizard.Y = Pos.Bottom (settingsFrame) + 1;
+                win.Add (_wizard);
+            }
+        };
 
-                                              // Add an optional FINAL last step
-                                              var finalFinalStep = new WizardStep { Title = "The VERY last step" };
-                                              wizard.AddStep (finalFinalStep);
+        showWizardButton.Accepting += (_, _) =>
+        {
+            _wizard = CreateWizard ();
+            app.Run (_wizard);
+            _wizard.Dispose ();
+        };
 
-                                              finalFinalStep.HelpText =
-                                                  "This step only shows if it was enabled on the other last step.";
-                                              finalFinalStep.Enabled = thirdStepEnabledCeckBox.CheckedState == CheckState.Checked;
+        app.Run (win);
+    }
 
-                                              finalFinalStepEnabledCeckBox.CheckedStateChanged += (s, e) =>
-                                                                                                  {
-                                                                                                      finalFinalStep.Enabled =
-                                                                                                          finalFinalStepEnabledCeckBox.CheckedState
-                                                                                                          == CheckState.Checked;
-                                                                                                  };
+    private Wizard CreateWizard ()
+    {
+        Wizard wizard = new ();
 
-                                              Application.Run (wizard);
-                                              wizard.Dispose ();
-                                          }
-                                          catch (FormatException)
-                                          {
-                                              actionLabel.Text = "Invalid Options";
-                                          }
-                                      };
-        win.Add (showWizardButton);
+        if (_titleEdit is { })
+        {
+            wizard.Title = _titleEdit.Text;
+        }
 
-        Application.Run (win);
-        win.Dispose ();
-        Application.Shutdown ();
+        wizard.MovingBack += (_, args) =>
+                             {
+                                 // Set Cancel to true to prevent moving back
+                                 args.Cancel = false;
+                                 _actionLabel!.Text = "Moving Back";
+                             };
+
+        wizard.MovingNext += (_, args) =>
+                             {
+                                 // Set Cancel to true to prevent moving next
+                                 args.Cancel = false;
+                                 _actionLabel!.Text = "Moving Next";
+                             };
+
+        wizard.Accepting += (s, args) =>
+                            {
+                                _actionLabel!.Text = "Finished";
+                                MessageBox.Query ((s as View)?.App!, "Wizard", "The Wizard has been completed and accepted!", "_Ok");
+
+                                if (wizard.IsRunning)
+                                {
+                                    // Don't set args.Handled to true to allow the wizard to close
+                                    args.Handled = false;
+                                }
+                                else
+                                {
+                                    wizard.App!.RequestStop();
+                                    args.Handled = true;
+                                }
+                            };
+
+        wizard.Cancelled += (s, args) =>
+                            {
+                                _actionLabel!.Text = "Cancelled";
+
+                                int? btn = MessageBox.Query ((s as View)?.App!, "Wizard", "Are you sure you want to cancel?", "_Yes", "_No");
+                                args.Cancel = btn is not 0;
+                            };
+
+        ((IDesignable)wizard).EnableForDesign ();
+
+        return wizard;
     }
-
-    private void Wizard_StepChanged (object sender, StepChangeEventArgs e) { throw new NotImplementedException (); }
 }

+ 2 - 1
Examples/UICatalog/UICatalog.cs

@@ -663,7 +663,8 @@ public class UICatalog
         // 'app' closed cleanly.
         foreach (View? inst in View.Instances)
         {
-            Debug.Assert (inst.WasDisposed);
+            //Debug.Assert (inst.WasDisposed);
+            Logging.Error ($"View instance not disposed: {inst}");
         }
 
         View.Instances.Clear ();

+ 4 - 31
Terminal.Gui/ViewBase/Adornment/Adornment.cs

@@ -31,6 +31,10 @@ public class Adornment : View, IDesignable
         CanFocus = false;
         TabStop = TabBehavior.NoStop;
         Parent = parent;
+
+        // By default, Adornments have no key bindings.
+        KeyBindings.Clear ();
+
     }
 
     /// <summary>The Parent of this Adornment (the View this Adornment surrounds).</summary>
@@ -246,37 +250,6 @@ public class Adornment : View, IDesignable
         return Thickness.Contains (outside, location);
     }
 
-    /// <summary>
-    ///     INTERNAL: Gets all Views (Subviews and Adornments) in the of <see cref="Adornment"/> hierarchcy that are at <paramref name="screenLocation"/>,
-    ///     regardless of whether they will be drawn or see mouse events or not. Views with <see cref="View.Visible"/> set to <see langword="false"/> will not be included.
-    ///     The list is ordered by depth. The deepest View is at the end of the list (the topmost View is at element 0).
-    /// </summary>
-    /// <param name="adornment">The root Adornment from which the search for subviews begins.</param>
-    /// <param name="screenLocation">The screen-relative location where the search for views is focused.</param>
-    /// <returns>A list of views that are located under the specified point.</returns>
-    internal static List<View?> GetViewsAtLocation (Adornment? adornment, in Point screenLocation)
-    {
-        List<View?> result = [];
-
-        if (adornment is null || adornment.Thickness == Thickness.Empty)
-        {
-            return result;
-        }
-
-        Point superViewRelativeLocation = adornment.Parent!.SuperView?.ScreenToViewport (screenLocation) ?? screenLocation;
-
-        if (adornment.Contains (superViewRelativeLocation))
-        {
-            List<View?> adornmentResult = GetViewsAtLocation (adornment as View, screenLocation);
-            if (adornmentResult.Count > 0)
-            {
-                result.AddRange (adornmentResult);
-            }
-        }
-
-        return result;
-    }
-
     #endregion View Overrides
 
     /// <inheritdoc/>

+ 8 - 5
Terminal.Gui/ViewBase/Adornment/Border.Arrangment.cs

@@ -371,7 +371,7 @@ public partial class Border
                     });
 
         AddCommand (
-                    Command.Tab,
+                    Command.NextTabStop,
                     () =>
                     {
                         // BUGBUG: If an arrangeable view has only arrangeable subviews, it's not possible to activate
@@ -386,7 +386,7 @@ public partial class Border
                     });
 
         AddCommand (
-                    Command.BackTab,
+                    Command.PreviousTabStop,
                     () =>
                     {
                         AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabStop);
@@ -396,14 +396,17 @@ public partial class Border
                     });
 
         HotKeyBindings.Add (Key.Esc, Command.Quit);
-        HotKeyBindings.Add (Application.ArrangeKey, Command.Quit);
+        HotKeyBindings.Add (App!.Keyboard.ArrangeKey, Command.Quit);
         HotKeyBindings.Add (Key.CursorUp, Command.Up);
         HotKeyBindings.Add (Key.CursorDown, Command.Down);
         HotKeyBindings.Add (Key.CursorLeft, Command.Left);
         HotKeyBindings.Add (Key.CursorRight, Command.Right);
 
-        HotKeyBindings.Add (Key.Tab, Command.Tab);
-        HotKeyBindings.Add (Key.Tab.WithShift, Command.BackTab);
+        KeyBindings.Remove (App!.Keyboard.NextTabKey);
+        KeyBindings.Remove (App!.Keyboard.PrevTabKey);
+
+        HotKeyBindings.Add (App!.Keyboard.NextTabKey, Command.NextTabStop);
+        HotKeyBindings.Add (App!.Keyboard.PrevTabKey, Command.PreviousTabStop);
     }
 
     private void ApplicationOnMouseEvent (object? sender, MouseEventArgs e)

+ 28 - 17
Terminal.Gui/ViewBase/Adornment/Margin.cs

@@ -53,7 +53,7 @@ public class Margin : Adornment
     // QUESTION: Why can't this just be the NeedsDisplay region?
     private Region? _cachedClip;
 
-    internal Region? GetCachedClip () { return _cachedClip; }
+    internal Region? GetCachedClip () => _cachedClip;
 
     internal void ClearCachedClip () { _cachedClip = null; }
 
@@ -67,15 +67,18 @@ public class Margin : Adornment
     }
 
     /// <summary>
-    ///     INTERNAL API - Draws the transparent margins for the specified views. This is called from <see cref="View.Draw(DrawContext)"/> on each
+    ///     INTERNAL API - Draws the transparent margins for the specified views. This is called from
+    ///     <see cref="View.Draw(DrawContext)"/> on each
     ///     iteration of the main loop after all Views have been drawn.
     /// </summary>
     /// <remarks>
     ///     Non-transparent margins are drawn as-normal in <see cref="View.DrawAdornments"/>.
     /// </remarks>
     /// <param name="views"></param>
-    /// <returns><see langword="true"/></returns>
-    internal static bool DrawTransparentMargins (IEnumerable<View> views)
+    /// <returns>
+    ///     <see langword="true"/>
+    /// </returns>
+    internal static bool DrawMargins (IEnumerable<View> views)
     {
         Stack<View> stack = new (views);
 
@@ -96,7 +99,10 @@ public class Margin : Adornment
                 margin.ClearCachedClip ();
             }
 
-            foreach (View subview in view.SubViews.OrderBy (v => v.HasFocus && v.ShadowStyle != ShadowStyle.None).Reverse ())
+            // Do not include Margin views of subviews; not supported
+            foreach (View subview in view.GetSubViews (false, includePadding: true, includeBorder: true)
+                                         .OrderBy (v => v.ShadowStyle != ShadowStyle.None)
+                                         .Reverse ())
             {
                 stack.Push (subview);
             }
@@ -141,17 +147,13 @@ public class Margin : Adornment
         if (ShadowStyle != ShadowStyle.None)
         {
             // Don't clear where the shadow goes
-            screen = Rectangle.Inflate (screen, -ShadowSize.Width, -ShadowSize.Height);
         }
 
         return true;
     }
 
-    /// <inheritdoc />
-    protected override bool OnDrawingText ()
-    {
-        return ViewportSettings.HasFlag (ViewportSettingsFlags.Transparent);
-    }
+    /// <inheritdoc/>
+    protected override bool OnDrawingText () => ViewportSettings.HasFlag (ViewportSettingsFlags.Transparent);
 
     #region Shadow
 
@@ -186,14 +188,23 @@ public class Margin : Adornment
         if (ShadowStyle != ShadowStyle.None)
         {
             // Turn off shadow
-            _originalThickness = new (Thickness.Left, Thickness.Top, Math.Max (Thickness.Right - ShadowSize.Width, 0), Math.Max (Thickness.Bottom - ShadowSize.Height, 0));
+            _originalThickness = new (
+                                      Thickness.Left,
+                                      Thickness.Top,
+                                      Math.Max (Thickness.Right - ShadowSize.Width, 0),
+                                      Math.Max (Thickness.Bottom - ShadowSize.Height, 0));
         }
 
         if (style != ShadowStyle.None)
         {
             // Turn on shadow
             _isThicknessChanging = true;
-            Thickness = new (_originalThickness.Value.Left, _originalThickness.Value.Top, _originalThickness.Value.Right + ShadowSize.Width, _originalThickness.Value.Bottom + ShadowSize.Height);
+
+            Thickness = new (
+                             _originalThickness.Value.Left,
+                             _originalThickness.Value.Top,
+                             _originalThickness.Value.Right + ShadowSize.Width,
+                             _originalThickness.Value.Bottom + ShadowSize.Height);
             _isThicknessChanging = false;
         }
 
@@ -279,7 +290,7 @@ public class Margin : Adornment
     {
         result = newValue;
 
-        bool wasValid = true;
+        var wasValid = true;
 
         if (newValue.Width < 0)
         {
@@ -288,7 +299,6 @@ public class Margin : Adornment
             wasValid = false;
         }
 
-
         if (newValue.Height < 0)
         {
             result = ShadowStyle is ShadowStyle.Opaque or ShadowStyle.Transparent ? result with { Height = 1 } : originalValue;
@@ -301,7 +311,7 @@ public class Margin : Adornment
             return false;
         }
 
-        bool wasUpdated = false;
+        var wasUpdated = false;
 
         if ((ShadowStyle == ShadowStyle.Opaque && newValue.Width != 1) || (ShadowStyle == ShadowStyle.Transparent && newValue.Width < 1))
         {
@@ -341,6 +351,7 @@ public class Margin : Adornment
             // Note, for visual effects reasons, we only move horizontally.
             // TODO: Add a setting or flag that lets the view move vertically as well.
             _isThicknessChanging = true;
+
             Thickness = new (
                              Thickness.Left - PRESS_MOVE_HORIZONTAL,
                              Thickness.Top - PRESS_MOVE_VERTICAL,
@@ -369,6 +380,7 @@ public class Margin : Adornment
             // Note, for visual effects reasons, we only move horizontally.
             // TODO: Add a setting or flag that lets the view move vertically as well.
             _isThicknessChanging = true;
+
             Thickness = new (
                              Thickness.Left + PRESS_MOVE_HORIZONTAL,
                              Thickness.Top + PRESS_MOVE_VERTICAL,
@@ -421,5 +433,4 @@ public class Margin : Adornment
     }
 
     #endregion Shadow
-
 }

+ 56 - 11
Terminal.Gui/ViewBase/Adornment/Padding.cs

@@ -1,5 +1,3 @@
-
-
 namespace Terminal.Gui.ViewBase;
 
 /// <summary>The Padding for a <see cref="View"/>. Accessed via <see cref="View.Padding"/></summary>
@@ -10,24 +8,25 @@ public class Padding : Adornment
 {
     /// <inheritdoc/>
     public Padding ()
-    { /* Do nothing; A parameter-less constructor is required to support all views unit tests. */
+    {
+        /* Do nothing; A parameter-less constructor is required to support all views unit tests. */
     }
 
     /// <inheritdoc/>
     public Padding (View parent) : base (parent)
     {
-        /* Do nothing; View.CreateAdornment requires a constructor that takes a parent */
+        CanFocus = true;
+        TabStop = TabBehavior.NoStop;
     }
 
-
     /// <summary>Called when a mouse event occurs within the Padding.</summary>
     /// <remarks>
-    /// <para>
-    /// The coordinates are relative to <see cref="View.Viewport"/>.
-    /// </para>
-    /// <para>
-    /// A mouse click on the Padding will cause the Parent to focus.
-    /// </para>
+    ///     <para>
+    ///         The coordinates are relative to <see cref="View.Viewport"/>.
+    ///     </para>
+    ///     <para>
+    ///         A mouse click on the Padding will cause the Parent to focus.
+    ///     </para>
     /// </remarks>
     /// <param name="mouseEvent"></param>
     /// <returns><see langword="true"/>, if the event was handled, <see langword="false"/> otherwise.</returns>
@@ -44,6 +43,7 @@ public class Padding : Adornment
             {
                 Parent.SetFocus ();
                 Parent.SetNeedsDraw ();
+
                 return mouseEvent.Handled = true;
             }
         }
@@ -51,4 +51,49 @@ public class Padding : Adornment
         return false;
     }
 
+    /// <summary>
+    ///     Gets all SubViews of this Padding, optionally including SubViews of the Padding's Parent.
+    /// </summary>
+    /// <param name="includeMargin">
+    ///     Ignored.
+    /// </param>
+    /// <param name="includeBorder">
+    ///     Ignored.
+    /// </param>
+    /// <param name="includePadding">
+    ///     If <see langword="true"/>, includes SubViews from <see cref="Padding"/>. If <see langword="false"/> (default),
+    ///     returns only the direct SubViews
+    ///     of this Padding.
+    /// </param>
+    /// <returns>
+    ///     A read-only collection containing all SubViews. If <paramref name="includePadding"/> is
+    ///     <see langword="true"/>, the collection includes SubViews from this Padding's direct SubViews as well
+    ///     as SubViews from the Padding's Parent.
+    /// </returns>
+    /// <remarks>
+    ///     <para>
+    ///         This method returns a snapshot of the SubViews at the time of the call. The collection is
+    ///         safe to iterate even if SubViews are added or removed during iteration.
+    ///     </para>
+    ///     <para>
+    ///         The order of SubViews in the returned collection is:
+    ///         <list type="number">
+    ///             <item>Direct SubViews of this Padding</item>
+    ///             <item>SubViews of Parent (if <paramref name="includePadding"/> is <see langword="true"/>)</item>
+    ///         </list>
+    ///     </para>
+    /// </remarks>
+    public override IReadOnlyCollection<View> GetSubViews (bool includeMargin = false, bool includeBorder = false, bool includePadding = false)
+    {
+        List<View> subViewsOfThisAdornment = new (base.GetSubViews (false, false, includePadding));
+
+        if (includePadding && Parent is { })
+        {
+            // Include SubViews from Parent. Since we are a Padding of Parent do not
+            // request Adornments again to avoid infinite recursion.
+            subViewsOfThisAdornment.AddRange (Parent.GetSubViews (false, false, false));
+        }
+
+        return subViewsOfThisAdornment;
+    }
 }

+ 3 - 4
Terminal.Gui/ViewBase/View.Adornments.cs

@@ -1,5 +1,4 @@
-
-namespace Terminal.Gui.ViewBase;
+namespace Terminal.Gui.ViewBase;
 
 public partial class View // Adornments
 {
@@ -158,7 +157,7 @@ public partial class View // Adornments
     /// <summary>
     ///     Called when the <see cref="BorderStyle"/> has changed.
     /// </summary>
-    protected virtual bool OnBorderStyleChanged () { return false; }
+    protected virtual bool OnBorderStyleChanged () => false;
 
     /// <summary>
     ///     Fired when the <see cref="BorderStyle"/> has changed.
@@ -230,7 +229,7 @@ public partial class View // Adornments
     /// <returns>A thickness that describes the sum of the Adornments' thicknesses.</returns>
     public Thickness GetAdornmentsThickness ()
     {
-        Thickness result = Thickness.Empty;
+        var result = Thickness.Empty;
 
         if (Margin is { })
         {

+ 52 - 36
Terminal.Gui/ViewBase/View.Drawing.cs

@@ -1,5 +1,4 @@
 using System.ComponentModel;
-using System.Diagnostics;
 
 namespace Terminal.Gui.ViewBase;
 
@@ -9,14 +8,17 @@ public partial class View // Drawing APIs
     ///     Draws a set of peer views (views that share the same SuperView).
     /// </summary>
     /// <param name="views">The peer views to draw.</param>
-    /// <param name="force">If <see langword="true"/>, <see cref="View.SetNeedsDraw()"/> will be called on each view to force it to be drawn.</param>
+    /// <param name="force">
+    ///     If <see langword="true"/>, <see cref="View.SetNeedsDraw()"/> will be called on each view to force
+    ///     it to be drawn.
+    /// </param>
     internal static void Draw (IEnumerable<View> views, bool force)
     {
         // **Snapshot once** — every recursion level gets its own frozen array
         View [] viewsArray = views.Snapshot ();
 
         // The draw context is used to track the region drawn by each view.
-        DrawContext context = new DrawContext ();
+        var context = new DrawContext ();
 
         foreach (View view in viewsArray)
         {
@@ -29,7 +31,7 @@ public partial class View // Drawing APIs
         }
 
         // Draw Transparent margins last to ensure they are drawn on top of the content.
-        Margin.DrawTransparentMargins (viewsArray);
+        Margin.DrawMargins (viewsArray);
 
         // DrawMargins may have caused some views have NeedsDraw/NeedsSubViewDraw set; clear them all.
         foreach (View view in viewsArray)
@@ -42,6 +44,7 @@ public partial class View // Drawing APIs
         // when peer subviews still need drawing), so we must do it here after ALL peers are processed.
         // We only clear the flag if ALL the SuperView's SubViews no longer need drawing.
         View? lastSuperView = null;
+
         foreach (View view in viewsArray)
         {
             if (view is not Adornment && view.SuperView is { } && view.SuperView != lastSuperView)
@@ -69,7 +72,8 @@ public partial class View // Drawing APIs
     ///         or <see cref="NeedsLayout"/> set.
     ///     </para>
     ///     <para>
-    ///         See the View Drawing Deep Dive for more information: <see href="https://gui-cs.github.io/Terminal.Gui/docs/drawing.html"/>.
+    ///         See the View Drawing Deep Dive for more information:
+    ///         <see href="https://gui-cs.github.io/Terminal.Gui/docs/drawing.html"/>.
     ///     </para>
     /// </remarks>
     public void Draw (DrawContext? context = null)
@@ -78,6 +82,7 @@ public partial class View // Drawing APIs
         {
             return;
         }
+
         Region? originalClip = GetClip ();
 
         // TODO: This can be further optimized by checking NeedsDraw below and only
@@ -281,7 +286,7 @@ public partial class View // Drawing APIs
     {
         // Only draw Margin here if it is not Transparent. Transparent Margins are drawn in a separate pass in the static View.Draw
         // via Margin.DrawTransparentMargins.
-        if (Margin is { } && !Margin.ViewportSettings.HasFlag(ViewportSettingsFlags.Transparent) && Margin.Thickness != Thickness.Empty)
+        if (Margin is { } && !Margin.ViewportSettings.HasFlag (ViewportSettingsFlags.Transparent) && Margin.Thickness != Thickness.Empty)
         {
             Margin?.Draw ();
         }
@@ -298,7 +303,7 @@ public partial class View // Drawing APIs
             Padding?.Draw ();
         }
 
-        if (Margin is { } && Margin.Thickness != Thickness.Empty/* && Margin.ShadowStyle == ShadowStyle.None*/)
+        if (Margin is { } && Margin.Thickness != Thickness.Empty /* && Margin.ShadowStyle == ShadowStyle.None*/)
         {
             //Margin?.Draw ();
         }
@@ -327,7 +332,7 @@ public partial class View // Drawing APIs
     ///     false (the default), this method will cause the <see cref="LineCanvas"/> be prepared to be rendered.
     /// </summary>
     /// <returns><see langword="true"/> to stop further drawing of the Adornments.</returns>
-    protected virtual bool OnDrawingAdornments () { return false; }
+    protected virtual bool OnDrawingAdornments () => false;
 
     #endregion DrawAdornments
 
@@ -347,6 +352,7 @@ public partial class View // Drawing APIs
         {
             // BUGBUG: We should add the Viewport to context.DrawRegion here?
             SetNeedsDraw ();
+
             return;
         }
 
@@ -362,7 +368,7 @@ public partial class View // Drawing APIs
     ///     Called when the <see cref="Viewport"/> is to be cleared.
     /// </summary>
     /// <returns><see langword="true"/> to stop further clearing.</returns>
-    protected virtual bool OnClearingViewport () { return false; }
+    protected virtual bool OnClearingViewport () => false;
 
     /// <summary>Event invoked when the <see cref="Viewport"/> is to be cleared.</summary>
     /// <remarks>
@@ -463,13 +469,13 @@ public partial class View // Drawing APIs
     /// </summary>
     /// <param name="context">The draw context to report drawn areas to.</param>
     /// <returns><see langword="true"/> to stop further drawing of  <see cref="Text"/>.</returns>
-    protected virtual bool OnDrawingText (DrawContext? context) { return false; }
+    protected virtual bool OnDrawingText (DrawContext? context) => false;
 
     /// <summary>
     ///     Called when the <see cref="Text"/> of the View is to be drawn.
     /// </summary>
     /// <returns><see langword="true"/> to stop further drawing of  <see cref="Text"/>.</returns>
-    protected virtual bool OnDrawingText () { return false; }
+    protected virtual bool OnDrawingText () => false;
 
     /// <summary>Raised when the <see cref="Text"/> of the View is to be drawn.</summary>
     /// <returns>
@@ -495,11 +501,11 @@ public partial class View // Drawing APIs
         if (Driver is { })
         {
             TextFormatter.Draw (
-                                 Driver,
-                                 drawRect,
-                                 HasFocus ? GetAttributeForRole (VisualRole.Focus) : GetAttributeForRole (VisualRole.Normal),
-                                 HasFocus ? GetAttributeForRole (VisualRole.HotFocus) : GetAttributeForRole (VisualRole.HotNormal),
-                                 Rectangle.Empty);
+                                Driver,
+                                drawRect,
+                                HasFocus ? GetAttributeForRole (VisualRole.Focus) : GetAttributeForRole (VisualRole.Normal),
+                                HasFocus ? GetAttributeForRole (VisualRole.HotFocus) : GetAttributeForRole (VisualRole.HotNormal),
+                                Rectangle.Empty);
         }
 
         // We assume that the text has been drawn over the entire area; ensure that the SubViews are redrawn.
@@ -529,9 +535,7 @@ public partial class View // Drawing APIs
         DrawingContent?.Invoke (this, dev);
 
         if (dev.Cancel)
-        {
-            return;
-        }
+        { }
 
         // No default drawing; let event handlers or overrides handle it
     }
@@ -546,15 +550,20 @@ public partial class View // Drawing APIs
     ///         Override this method to draw custom content for your View.
     ///     </para>
     ///     <para>
-    ///         <b>Transparency Support:</b> If your View has <see cref="ViewportSettings"/> with <see cref="ViewportSettingsFlags.Transparent"/>
+    ///         <b>Transparency Support:</b> If your View has <see cref="ViewportSettings"/> with
+    ///         <see cref="ViewportSettingsFlags.Transparent"/>
     ///         set, you should report the exact regions you draw to via the <paramref name="context"/> parameter. This allows
-    ///         the transparency system to exclude only the drawn areas from the clip region, letting views beneath show through
+    ///         the transparency system to exclude only the drawn areas from the clip region, letting views beneath show
+    ///         through
     ///         in the areas you didn't draw.
     ///     </para>
     ///     <para>
-    ///         Use <see cref="DrawContext.AddDrawnRectangle"/> for simple rectangular areas, or <see cref="DrawContext.AddDrawnRegion"/>
-    ///         for complex, non-rectangular shapes. All coordinates passed to these methods must be in <b>screen-relative coordinates</b>.
-    ///         Use <see cref="View.ViewportToScreen(in Rectangle)"/> or <see cref="View.ContentToScreen(in Point)"/> to convert from
+    ///         Use <see cref="DrawContext.AddDrawnRectangle"/> for simple rectangular areas, or
+    ///         <see cref="DrawContext.AddDrawnRegion"/>
+    ///         for complex, non-rectangular shapes. All coordinates passed to these methods must be in
+    ///         <b>screen-relative coordinates</b>.
+    ///         Use <see cref="View.ViewportToScreen(in Rectangle)"/> or <see cref="View.ContentToScreen(in Point)"/> to
+    ///         convert from
     ///         viewport-relative or content-relative coordinates.
     ///     </para>
     ///     <para>
@@ -583,24 +592,31 @@ public partial class View // Drawing APIs
     ///         }
     ///     </code>
     /// </remarks>
-    protected virtual bool OnDrawingContent (DrawContext? context) { return false; }
+    protected virtual bool OnDrawingContent (DrawContext? context) => false;
 
     /// <summary>Raised when the View's content is to be drawn.</summary>
     /// <remarks>
     ///     <para>
-    ///         Subscribe to this event to draw custom content for the View. Use the drawing methods available on <see cref="View"/>
-    ///         such as <see cref="View.AddRune(int, int, Rune)"/>, <see cref="View.AddStr(string)"/>, and <see cref="View.FillRect(Rectangle, Rune)"/>.
+    ///         Subscribe to this event to draw custom content for the View. Use the drawing methods available on
+    ///         <see cref="View"/>
+    ///         such as <see cref="View.AddRune(int, int, Rune)"/>, <see cref="View.AddStr(string)"/>, and
+    ///         <see cref="View.FillRect(Rectangle, Rune)"/>.
     ///     </para>
     ///     <para>
-    ///         The event is invoked after <see cref="ClearingViewport"/> and <see cref="Text"/> have been drawn, but after <see cref="SubViews"/> have been drawn.
+    ///         The event is invoked after <see cref="ClearingViewport"/> and <see cref="Text"/> have been drawn, but after
+    ///         <see cref="SubViews"/> have been drawn.
     ///     </para>
     ///     <para>
-    ///         <b>Transparency Support:</b> If the View has <see cref="ViewportSettings"/> with <see cref="ViewportSettingsFlags.Transparent"/>
-    ///         set, use the <see cref="DrawEventArgs.DrawContext"/> to report which areas were actually drawn. This enables proper transparency
-    ///         by excluding only the drawn areas from the clip region. See <see cref="DrawContext"/> for details on reporting drawn regions.
+    ///         <b>Transparency Support:</b> If the View has <see cref="ViewportSettings"/> with
+    ///         <see cref="ViewportSettingsFlags.Transparent"/>
+    ///         set, use the <see cref="DrawEventArgs.DrawContext"/> to report which areas were actually drawn. This enables
+    ///         proper transparency
+    ///         by excluding only the drawn areas from the clip region. See <see cref="DrawContext"/> for details on reporting
+    ///         drawn regions.
     ///     </para>
     ///     <para>
-    ///         The <see cref="DrawEventArgs.NewViewport"/> property provides the view-relative rectangle describing the currently visible viewport into the View.
+    ///         The <see cref="DrawEventArgs.NewViewport"/> property provides the view-relative rectangle describing the
+    ///         currently visible viewport into the View.
     ///     </para>
     /// </remarks>
     public event EventHandler<DrawEventArgs>? DrawingContent;
@@ -643,13 +659,13 @@ public partial class View // Drawing APIs
     /// </summary>
     /// <param name="context">The draw context to report drawn areas to, or null if not tracking.</param>
     /// <returns><see langword="true"/> to stop further drawing of <see cref="SubViews"/>.</returns>
-    protected virtual bool OnDrawingSubViews (DrawContext? context) { return false; }
+    protected virtual bool OnDrawingSubViews (DrawContext? context) => false;
 
     /// <summary>
     ///     Called when the <see cref="SubViews"/> are to be drawn.
     /// </summary>
     /// <returns><see langword="true"/> to stop further drawing of <see cref="SubViews"/>.</returns>
-    protected virtual bool OnDrawingSubViews () { return false; }
+    protected virtual bool OnDrawingSubViews () => false;
 
     /// <summary>Raised when the <see cref="SubViews"/> are to be drawn.</summary>
     /// <remarks>
@@ -680,6 +696,7 @@ public partial class View // Drawing APIs
             {
                 //view.SetNeedsDraw ();
             }
+
             view.Draw (context);
 
             if (view.SuperViewRendersLineCanvas)
@@ -711,7 +728,7 @@ public partial class View // Drawing APIs
     ///     Called when the <see cref="View.LineCanvas"/> is to be rendered. See <see cref="RenderLineCanvas"/>.
     /// </summary>
     /// <returns><see langword="true"/> to stop further drawing of <see cref="LineCanvas"/>.</returns>
-    protected virtual bool OnRenderingLineCanvas () { return false; }
+    protected virtual bool OnRenderingLineCanvas () => false;
 
     /// <summary>The canvas that any line drawing that is to be shared by subviews of this view should add lines to.</summary>
     /// <remarks><see cref="Border"/> adds lines to this LineCanvas.</remarks>
@@ -922,5 +939,4 @@ public partial class View // Drawing APIs
     public event EventHandler<DrawEventArgs>? DrawComplete;
 
     #endregion DrawComplete
-
 }

+ 81 - 7
Terminal.Gui/ViewBase/View.Hierarchy.cs

@@ -1,5 +1,4 @@
 using System.Diagnostics;
-using System.Diagnostics.CodeAnalysis;
 
 namespace Terminal.Gui.ViewBase;
 
@@ -19,6 +18,73 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
     /// </remarks>
     public IReadOnlyCollection<View> SubViews => InternalSubViews?.AsReadOnly () ?? _empty;
 
+    /// <summary>
+    ///     Gets all SubViews of this View, optionally including SubViews of the View's Adornments
+    ///     (Margin, Border, and Padding).
+    /// </summary>
+    /// <param name="includeMargin">
+    ///     If <see langword="true"/>, includes SubViews from <see cref="Margin"/>. If <see langword="false"/> (default),
+    ///     returns only the direct SubViews
+    ///     of this View.
+    /// </param>
+    /// <param name="includeBorder">
+    ///     If <see langword="true"/>, includes SubViews from <see cref="Border"/>. If <see langword="false"/> (default),
+    ///     returns only the direct SubViews
+    ///     of this View.
+    /// </param>
+    /// <param name="includePadding">
+    ///     If <see langword="true"/>, includes SubViews from <see cref="Padding"/>. If <see langword="false"/> (default),
+    ///     returns only the direct SubViews
+    ///     of this View.
+    /// </param>
+    /// <returns>
+    ///     A read-only collection containing all SubViews. If <paramref name="includeMargin"/> is
+    ///     <see langword="true"/>, the collection includes SubViews from this View's direct SubViews as well
+    ///     as SubViews from the Margin, Border, and Padding adornments.
+    /// </returns>
+    /// <remarks>
+    ///     <para>
+    ///         This method returns a snapshot of the SubViews at the time of the call. The collection is
+    ///         safe to iterate even if SubViews are added or removed during iteration.
+    ///     </para>
+    ///     <para>
+    ///         The order of SubViews in the returned collection is:
+    ///         <list type="number">
+    ///             <item>Direct SubViews of this View</item>
+    ///             <item>SubViews of Margin (if <paramref name="includeMargin"/> is <see langword="true"/>)</item>
+    ///             <item>SubViews of Border (if <paramref name="includeBorder"/> is <see langword="true"/>)</item>
+    ///             <item>SubViews of Padding (if <paramref name="includePadding"/> is <see langword="true"/>)</item>
+    ///         </list>
+    ///     </para>
+    /// </remarks>
+    public virtual IReadOnlyCollection<View> GetSubViews (bool includeMargin = false, bool includeBorder = false, bool includePadding = false)
+    {
+        List<View> result = [];
+
+        // Add direct SubViews
+        result.AddRange (InternalSubViews);
+
+        if (includeMargin && Margin is { SubViews: { Count: > 0 } } && Margin.Thickness != Thickness.Empty)
+        {
+            // Add Margin SubViews
+            result.AddRange (Margin.SubViews);
+        }
+
+        if (includeBorder && Border is { SubViews: { Count: > 0 } } && Border.Thickness != Thickness.Empty)
+        {
+            // Add Border SubViews
+            result.AddRange (Border.SubViews);
+        }
+
+        if (includePadding && Padding is { SubViews: { Count: > 0 } } && Padding.Thickness != Thickness.Empty)
+        {
+            // Add Padding SubViews
+            result.AddRange (Padding.SubViews);
+        }
+
+        return result.AsReadOnly ();
+    }
+
     private View? _superView;
 
     /// <summary>
@@ -40,7 +106,7 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
     {
         if (_superView == value)
         {
-           return true;
+            return true;
         }
 
         return CWPPropertyHelper.ChangeProperty (
@@ -87,7 +153,6 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
 
     #region AddRemove
 
-    // TODO: Make this non-virtual once WizardStep is refactored to use events
     /// <summary>Adds a SubView (child) to this view.</summary>
     /// <remarks>
     ///     <para>
@@ -117,7 +182,7 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
     /// <seealso cref="SuperViewChanging"/>
     /// <seealso cref="OnSuperViewChanged"/>
     /// <seealso cref="SuperViewChanged"/>
-    public virtual View? Add (View? view)
+    public View? Add (View? view)
     {
         if (view is null)
         {
@@ -136,6 +201,15 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
             Logging.Warning ($"{view} has already been Added to {this}.");
         }
 
+        // TODO: Add AddingSubView event
+        if (this is Margin)
+        {
+            if (view is not ShadowView)
+            {
+                throw new InvalidOperationException ("SubViews of Margin are not supported.");
+            }
+        }
+
         // TODO: Make this thread safe
         InternalSubViews.Add (view);
 
@@ -143,6 +217,7 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
         if (!view.SetSuperView (this))
         {
             InternalSubViews.Remove (view);
+
             // The change was cancelled
             return null;
         }
@@ -226,7 +301,6 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
     /// </remarks>
     public event EventHandler<SuperViewChangedEventArgs>? SubViewAdded;
 
-    // TODO: Make this non-virtual once WizardStep is refactored to use events
     /// <summary>Removes a SubView added via <see cref="Add(View)"/> or <see cref="Add(View[])"/> from this View.</summary>
     /// <remarks>
     ///     <para>
@@ -253,7 +327,7 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
     /// <seealso cref="SuperViewChanging"/>
     /// <seealso cref="OnSuperViewChanged"/>
     /// <seealso cref="SuperViewChanged"/>
-    public virtual View? Remove (View? view)
+    public View? Remove (View? view)
     {
         if (view is null)
         {
@@ -308,7 +382,7 @@ public partial class View // SuperView/SubView hierarchy management (SuperView,
             return null;
         }
 
-        Debug.Assert(view.SuperView is null);
+        Debug.Assert (view.SuperView is null);
         InternalSubViews.Remove (view);
 
         // Clean up focus stuff

+ 17 - 26
Terminal.Gui/ViewBase/View.Navigation.cs

@@ -1,6 +1,5 @@
 using System.Diagnostics;
 
-
 namespace Terminal.Gui.ViewBase;
 
 public partial class View // Focus and cross-view navigation management (TabStop, TabIndex, etc...)
@@ -97,12 +96,12 @@ public partial class View // Focus and cross-view navigation management (TabStop
                     return false;
                 }
 
-                // TabGroup is special-cased. 
+                // TabGroup is special-cased.
                 if (focused?.TabStop == TabBehavior.TabGroup)
                 {
-                    if (SuperView?.GetFocusChain (direction, TabBehavior.TabGroup)?.Length > 0)
+                    if (SuperView?.GetFocusChain (direction, TabBehavior.TabGroup).Length > 0)
                     {
-                        // Our superview has a TabGroup subview; signal we couldn't move so we nav out to it
+                        // Our superview has a TabGroup subview; signal we couldn't move so nav out to it
                         return false;
                     }
                 }
@@ -244,7 +243,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
     ///     <see langword="true"/>, if the focus advance is to be cancelled, <see langword="false"/>
     ///     otherwise.
     /// </returns>
-    protected virtual bool OnAdvancingFocus (NavigationDirection direction, TabBehavior? behavior) { return false; }
+    protected virtual bool OnAdvancingFocus (NavigationDirection direction, TabBehavior? behavior) => false;
 
     /// <summary>
     ///     Raised when <see cref="View.AdvanceFocus"/> is about to advance focus.
@@ -348,7 +347,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
     {
         get
         {
-            View? focused = SubViews.FirstOrDefault (v => v.HasFocus);
+            View? focused = GetSubViews (includePadding: true).FirstOrDefault (v => v.HasFocus);
 
             if (focused is { })
             {
@@ -755,7 +754,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
     ///     <see langword="true"/>, if the change to <see cref="View.HasFocus"/> is to be cancelled, <see langword="false"/>
     ///     otherwise.
     /// </returns>
-    protected virtual bool OnHasFocusChanging (bool currentHasFocus, bool newHasFocus, View? currentFocused, View? newFocused) { return false; }
+    protected virtual bool OnHasFocusChanging (bool currentHasFocus, bool newHasFocus, View? currentFocused, View? newFocused) => false;
 
     /// <summary>
     ///     Raised when <see cref="View.HasFocus"/> is about to change.
@@ -841,7 +840,7 @@ public partial class View // Focus and cross-view navigation management (TabStop
                 // Temporarily ensure this view can't get focus
                 bool prevCanFocus = _canFocus;
                 _canFocus = false;
-                bool restoredFocus = applicationFocused!.RestoreFocus ();
+                bool restoredFocus = applicationFocused.RestoreFocus ();
                 _canFocus = prevCanFocus;
 
                 if (restoredFocus)
@@ -922,9 +921,6 @@ public partial class View // Focus and cross-view navigation management (TabStop
             return;
         }
 
-        // Get whatever peer has focus, if any so we can update our superview's _previouslyMostFocused
-        View? focusedPeer = superViewOrParent?.Focused;
-
         // Set HasFocus false
         _hasFocus = false;
 
@@ -987,7 +983,9 @@ public partial class View // Focus and cross-view navigation management (TabStop
     ///         This event cannot be cancelled.
     ///     </para>
     /// </remarks>
+#pragma warning disable CS0067 // Event is never used
     public event EventHandler<HasFocusEventArgs>? HasFocusChanged;
+#pragma warning restore CS0067 // Event is never used
 
     #endregion HasFocus
 
@@ -1007,35 +1005,28 @@ public partial class View // Focus and cross-view navigation management (TabStop
 
         if (behavior.HasValue)
         {
-            filteredSubViews = InternalSubViews?.Where (v => v.TabStop == behavior && v is { CanFocus: true, Visible: true, Enabled: true });
+            filteredSubViews = GetSubViews (includePadding: true)
+                .Where (v => v.TabStop == behavior && v is { CanFocus: true, Visible: true, Enabled: true });
         }
         else
         {
-            filteredSubViews = InternalSubViews?.Where (v => v is { CanFocus: true, Visible: true, Enabled: true });
-        }
-
-        // How about in Adornments? 
-        if (Padding is { CanFocus: true, Visible: true, Enabled: true } && Padding.TabStop == behavior)
-        {
-            filteredSubViews = filteredSubViews?.Append (Padding);
+            filteredSubViews = GetSubViews (includePadding: true)
+                .Where (v => v is { CanFocus: true, Visible: true, Enabled: true });
         }
 
-        if (Border is { CanFocus: true, Visible: true, Enabled: true } && Border.TabStop == behavior)
+        if (Padding is { CanFocus: true, Visible: true, Enabled: true } && Padding.TabStop == behavior && Padding.Thickness != Thickness.Empty)
         {
-            filteredSubViews = filteredSubViews?.Append (Border);
+            filteredSubViews = filteredSubViews.Append (Padding);
         }
 
-        if (Margin is { CanFocus: true, Visible: true, Enabled: true } && Margin.TabStop == behavior)
-        {
-            filteredSubViews = filteredSubViews?.Append (Margin);
-        }
+        // Border and Margin do not participate in focus chain navigation.
 
         if (direction == NavigationDirection.Backward)
         {
             filteredSubViews = filteredSubViews?.Reverse ();
         }
 
-        return filteredSubViews?.ToArray () ?? Array.Empty<View> ();
+        return filteredSubViews?.ToArray () ?? [];
     }
 
     private TabBehavior? _tabStop;

+ 2 - 2
Terminal.Gui/ViewBase/View.ScrollBars.cs

@@ -132,7 +132,7 @@ public partial class View
 
     private void ConfigureVerticalScrollBarEvents (ScrollBar scrollBar)
     {
-        Padding!.Thickness = Padding.Thickness with { Right = scrollBar.Visible ? Padding.Thickness.Right + 1 : 0 };
+        Padding!.Thickness = Padding.Thickness with { Right = scrollBar.Visible ? Padding.Thickness.Right + 1 : Padding.Thickness.Right };
 
         scrollBar.PositionChanged += (_, args) =>
                                      {
@@ -153,7 +153,7 @@ public partial class View
 
     private void ConfigureHorizontalScrollBarEvents (ScrollBar scrollBar)
     {
-        Padding!.Thickness = Padding.Thickness with { Bottom = scrollBar.Visible ? Padding.Thickness.Bottom + 1 : 0 };
+        Padding!.Thickness = Padding.Thickness with { Bottom = scrollBar.Visible ? Padding.Thickness.Bottom + 1 : Padding.Thickness.Bottom };
 
         scrollBar.PositionChanged += (_, args) =>
                                      {

+ 27 - 23
Terminal.Gui/ViewBase/View.cs

@@ -500,17 +500,27 @@ public partial class View : IDisposable, ISupportInitializeNotification
                 return;
             }
 
-            if (!OnTitleChanging (ref value))
+            if (OnTitleChanging (ref value))
             {
-                string old = _title;
-                _title = value;
-                TitleTextFormatter.Text = _title;
-
-                SetTitleTextFormatterSize ();
-                SetHotKeyFromTitle ();
-                SetNeedsDraw ();
-                OnTitleChanged ();
+                return;
             }
+            CancelEventArgs<string> args = new (ref _title, ref value);
+            TitleChanging?.Invoke (this, args);
+
+            if (args.Cancel)
+            {
+                return;
+            }
+
+            _title = value;
+            TitleTextFormatter.Text = _title;
+
+            SetTitleTextFormatterSize ();
+            SetHotKeyFromTitle ();
+            SetNeedsDraw ();
+
+            OnTitleChanged ();
+            TitleChanged?.Invoke (this, new (in _title));
         }
     }
 
@@ -524,26 +534,13 @@ public partial class View : IDisposable, ISupportInitializeNotification
                                                   1);
     }
 
-    // TODO: Change this event to match the standard TG event model.
-    /// <summary>Called when the <see cref="View.Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.</summary>
-    protected void OnTitleChanged () { TitleChanged?.Invoke (this, new (in _title)); }
-
     /// <summary>
     ///     Called before the <see cref="View.Title"/> changes. Invokes the <see cref="TitleChanging"/> event, which can
     ///     be cancelled.
     /// </summary>
     /// <param name="newTitle">The new <see cref="View.Title"/> to be replaced.</param>
     /// <returns>`true` if an event handler canceled the Title change.</returns>
-    protected bool OnTitleChanging (ref string newTitle)
-    {
-        CancelEventArgs<string> args = new (ref _title, ref newTitle);
-        TitleChanging?.Invoke (this, args);
-
-        return args.Cancel;
-    }
-
-    /// <summary>Raised after the <see cref="View.Title"/> has been changed.</summary>
-    public event EventHandler<EventArgs<string>>? TitleChanged;
+    protected virtual bool OnTitleChanging (ref string newTitle) => false;
 
     /// <summary>
     ///     Raised when the <see cref="View.Title"/> is changing. Set <see cref="CancelEventArgs.Cancel"/> to `true`
@@ -551,6 +548,13 @@ public partial class View : IDisposable, ISupportInitializeNotification
     /// </summary>
     public event EventHandler<CancelEventArgs<string>>? TitleChanging;
 
+    /// <summary>Called when the <see cref="View.Title"/> has been changed. Invokes the <see cref="TitleChanged"/> event.</summary>
+    protected virtual void OnTitleChanged () { }
+
+    /// <summary>Raised after the <see cref="View.Title"/> has been changed.</summary>
+    public event EventHandler<EventArgs<string>>? TitleChanged;
+
+
     #endregion
 
 #if DEBUG_IDISPOSABLE

+ 4 - 0
Terminal.Gui/Views/TextInput/TextView.cs

@@ -4766,6 +4766,10 @@ public class TextView : View, IDesignable
                It supports word wrap and history for undo.
                """;
 
+        // This enables AllViews_HasFocus_Changed_Event to pass since it requires
+        // tab navigation to work
+        AllowsTab = false;
+
         return true;
     }
 

+ 268 - 352
Terminal.Gui/Views/Wizard/Wizard.cs

@@ -1,104 +1,159 @@
+using System.ComponentModel;
+
 namespace Terminal.Gui.Views;
 
 /// <summary>
-///     Provides navigation and a user interface (UI) to collect related data across multiple steps. Each step (
-///     <see cref="WizardStep"/>) can host arbitrary <see cref="View"/>s, much like a <see cref="Dialog"/>. Each step also
-///     has a pane for help text. Along the bottom of the Wizard view are customizable buttons enabling the user to
-///     navigate forward and backward through the Wizard.
+///     A multistep user interface for collecting related data. Each <see cref="WizardStep"/> can host arbitrary
+///     <see cref="View"/>s and display help text. Navigation buttons enable moving between steps.
 /// </summary>
 /// <remarks>
-///     The Wizard can be displayed either as a modal (pop-up) <see cref="Window"/> (like <see cref="Dialog"/>) or as
-///     an embedded <see cref="View"/>.
+///     Can be displayed as a modal (pop-up) or embedded view.
 /// </remarks>
 /// <example>
 ///     <code>
 /// using Terminal.Gui;
-/// using System.Text;
 /// 
-/// Application.Init();
+/// using IApplication app = Application.Create ();
+/// app.Init ();
 /// 
-/// var wizard = new Wizard ($"Setup Wizard");
+/// using Wizard wiz = new () { Title = "Setup Wizard" };
 /// 
-/// // Add 1st step
-/// var firstStep = new WizardStep ("End User License Agreement");
-/// wizard.AddStep(firstStep);
+/// // Add first step
+/// WizardStep firstStep = new () { Title = "License Agreement" };
 /// firstStep.NextButtonText = "Accept!";
-/// firstStep.HelpText = "This is the End User License Agreement.";
-/// 
-/// // Add 2nd step
-/// var secondStep = new WizardStep ("Second Step");
-/// wizard.AddStep(secondStep);
-/// secondStep.HelpText = "This is the help text for the Second Step.";
-/// var lbl = new Label () { Text = "Name:" };
-/// secondStep.Add(lbl);
+/// firstStep.HelpText = "End User License Agreement text.";
+/// wizard.AddStep(firstStep);
 /// 
-/// var name = new TextField { X = Pos.Right (lbl) + 1, Width = Dim.Fill () - 1 };
-/// secondStep.Add(name);
+/// // Add second step
+/// WizardStep secondStep = new () { Title = "User Info" };
+/// secondStep.HelpText = "Enter your information.";
+/// TextField name = new () { X = 0, Width = 20 };
+/// secondStep.Add (new Label { Text = "Name:" }, name);
+/// wizard.AddStep (secondStep);
 /// 
-/// wizard.Finished += (args) =>
+/// wizard.Accepting += (_, e) =>
 /// {
-///     MessageBox.Query("Wizard", $"Finished. The Name entered is '{name.Text}'", "Ok");
-///     Application.RequestStop();
+///     MessageBox.Query ("Complete", $"Name: {name.Text}", "Ok");
+///     e.Handled = true;
 /// };
 /// 
-/// Application.TopRunnable.Add (wizard);
-/// Application.Run ();
-/// Application.Shutdown ();
+/// app.Run (wizard);
 /// </code>
 /// </example>
-public class Wizard : Dialog
+public class Wizard : Runnable, IDesignable
 {
-    private readonly LinkedList<WizardStep> _steps = new ();
-    private WizardStep? _currentStep;
-    private bool _finishedPressed;
     private string _wizardTitle = string.Empty;
 
     /// <summary>
-    ///     Initializes a new instance of the <see cref="Wizard"/> class.
+    ///     Initializes a new instance of the <see cref="Wizard"/> class, centered with automatic sizing.
     /// </summary>
-    /// <remarks>
-    ///     The Wizard will be vertically and horizontally centered in the container. After initialization use <c>X</c>,
-    ///     <c>Y</c>, <c>Width</c>, and <c>Height</c> change size and position.
-    /// </remarks>
     public Wizard ()
     {
-        // TODO: LastEndRestStart will enable a "Quit" button to always appear at the far left
-        ButtonAlignment = Alignment.Start;
-        ButtonAlignmentModes |= AlignmentModes.IgnoreFirstOrLast;
-        BorderStyle = LineStyle.Double;
+        TabStop = TabBehavior.TabGroup;
+        X = Pos.Center ();
+        Y = Pos.Center ();
+        Width = Dim.Auto (minimumContentDim: Dim.Percent (80), maximumContentDim: Dim.Percent (90));
+        Height = Dim.Auto (minimumContentDim: Dim.Percent (10), maximumContentDim: Dim.Percent (90));
 
-        BackButton = new () { Text = Strings.wzBack };
+        SetStyle ();
+
+        BackButton = new ()
+        {
+            Text = Strings.wzBack,
+            X = 0,
+            Y = Pos.AnchorEnd ()
+        };
 
         NextFinishButton = new ()
         {
             Text = Strings.wzFinish,
-            IsDefault = true
+            IsDefault = true,
+            X = Pos.AnchorEnd (),
+            Y = Pos.AnchorEnd ()
         };
+        NextFinishButton.FrameChanged += (_, _) => { Padding!.Thickness = Padding.Thickness with { Bottom = NextFinishButton.Frame.Height }; };
+
+        AddCommand (Command.Quit, QuitHandler);
+        KeyBindings.Add (Application.QuitKey, Command.Quit);
+
+        return;
+
+        // Add key binding for Esc when not modal - fires Cancelled event
+        bool? QuitHandler (ICommandContext? ctx)
+        {
+            CancelEventArgs args = new ();
+            Cancelled?.Invoke (this, args);
+
+            return args.Cancel;
+        }
+    }
+
+    private void SetStyle ()
+    {
+        if (IsRunning)
+        {
+            SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Dialog);
+            Padding?.SetScheme (SchemeManager.GetScheme (Schemes.Base));
+            BorderStyle = Dialog.DefaultBorderStyle;
+            Arrangement |= ViewArrangement.Movable | ViewArrangement.Resizable;
+            base.ShadowStyle = Dialog.DefaultShadow;
+        }
+        else
+        {
+            SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Base);
+            Padding?.SetScheme (SchemeManager.GetScheme (Schemes.Dialog));
+            BorderStyle = LineStyle.Dotted;
+
+            // strip out movable and resizable
+            Arrangement &= ~(ViewArrangement.Movable | ViewArrangement.Resizable);
+            base.ShadowStyle = ShadowStyle.None;
+        }
+    }
+
+    /// <inheritdoc/>
+    protected override void OnTitleChanged ()
+    {
+        if (string.IsNullOrEmpty (_wizardTitle))
+        {
+            _wizardTitle = Title;
+        }
+    }
 
-        // Add a horiz separator
-        var separator = new Line { Orientation = Orientation.Horizontal, X = -1, Y = Pos.Top (BackButton) - 1, Length = Dim.Fill (-1) };
+    /// <inheritdoc/>
+    public override void EndInit ()
+    {
+        // Configure Padding
+        if (Padding is { })
+        {
+            // Add buttons to bottom Padding instead of using AddButton
+            Padding?.Add (BackButton);
+            Padding?.Add (NextFinishButton);
+        }
 
-        base.Add (separator);
-        AddButton (BackButton);
-        AddButton (NextFinishButton);
+        BackButton.Accepting += BackBtnOnAccepting;
+        NextFinishButton.Accepting += NextFinishBtnOnAccepting;
 
-        BackButton.Accepting += BackBtn_Accepting;
-        NextFinishButton.Accepting += NextFinishBtn_Accepting;
+        CurrentStep = GetFirstStep ();
+        base.EndInit ();
+    }
 
-        IsModalChanged += Wizard_IsModalChanged;
-        IsRunningChanged += Wizard_IsRunningChanged;
-        TitleChanged += Wizard_TitleChanged;
+    /// <inheritdoc/>
+    protected override void OnIsModalChanged (bool newIsModal)
+    {
+        SetStyle ();
 
-        SetNeedsLayout ();
+        base.OnIsModalChanged (newIsModal);
     }
 
     /// <summary>
-    ///     If the <see cref="CurrentStep"/> is not the first step in the wizard, this button causes the
-    ///     <see cref="MovingBack"/> event to be fired and the wizard moves to the previous step.
+    ///     The Back button. Navigates to the previous step and raises <see cref="MovingBack"/>.
+    ///     Hidden on the first step.
     /// </summary>
-    /// <remarks>Use the <see cref="MovingBack"></see> event to be notified when the user attempts to go back.</remarks>
     public Button BackButton { get; }
 
+    private readonly LinkedList<WizardStep> _steps = [];
+    private WizardStep? _currentStep;
+
     /// <summary>Gets or sets the currently active <see cref="WizardStep"/>.</summary>
     public WizardStep? CurrentStep
     {
@@ -106,113 +161,62 @@ public class Wizard : Dialog
         set => GoToStep (value);
     }
 
-    ///// <summary>
-    /////     Determines whether the <see cref="Wizard"/> is displayed as modal pop-up or not. The default is
-    /////     <see langword="true"/>. The Wizard will be shown with a frame and title and will behave like any
-    /////     <see cref="Runnable"/> window. If set to <c>false</c> the Wizard will have no frame and will behave like any
-    /////     embedded <see cref="View"/>. To use Wizard as an embedded View
-    /////     <list type="number">
-    /////         <item>
-    /////             <description>Set <see cref="Modal"/> to <c>false</c>.</description>
-    /////         </item>
-    /////         <item>
-    /////             <description>Add the Wizard to a containing view with <see cref="View.Add(View)"/>.</description>
-    /////         </item>
-    /////     </list>
-    /////     If a non-Modal Wizard is added to the application after
-    /////     <see cref="IApplication.Run(IRunnable, Func{Exception, bool})"/> has
-    /////     been called the first step must be explicitly set by setting <see cref="CurrentStep"/> to
-    /////     <see cref="GetNextStep()"/>:
-    /////     <code>
-    /////    wizard.CurrentStep = wizard.GetNextStep();
-    ///// </code>
-    ///// </summary>
-    //public new bool Modal
-    //{
-    //    get => base.Modal;
-    //    set
-    //    {
-    //        base.Modal = value;
-
-    //        foreach (WizardStep step in _steps)
-    //        {
-    //            SizeStep (step);
-    //        }
-
-    //        if (base.Modal)
-    //        {
-    //            SchemeName = "Dialog";
-    //            BorderStyle = LineStyle.Rounded;
-    //        }
-    //        else
-    //        {
-    //            CanFocus = true;
-    //            BorderStyle = LineStyle.None;
-    //        }
-    //    }
-    //}
-
     /// <summary>
-    ///     If the <see cref="CurrentStep"/> is the last step in the wizard, this button causes the <see cref="Finished"/>
-    ///     event to be fired and the wizard to close. If the step is not the last step, the <see cref="MovingNext"/> event
-    ///     will be fired and the wizard will move next step.
+    ///     The Next/Finish button. On the last step, raises <see cref="View.Accepting"/>.
+    ///     On other steps, raises <see cref="MovingNext"/> and navigates forward.
     /// </summary>
-    /// <remarks>
-    ///     Use the <see cref="MovingNext"></see> and <see cref="Finished"></see> events to be notified when the user
-    ///     attempts go to the next step or finish the wizard.
-    /// </remarks>
     public Button NextFinishButton { get; }
 
+    private Size _maxStepSize = Size.Empty;
+
     /// <summary>
-    ///     Adds a step to the wizard. The Next and Back buttons navigate through the added steps in the order they were
-    ///     added.
+    ///     Adds a step to the wizard. Steps are navigated in the order added.
     /// </summary>
-    /// <param name="newStep"></param>
-    /// <remarks>The "Next..." button of the last step added will read "Finish" (unless changed from default).</remarks>
+    /// <param name="newStep">The step to add.</param>
     public void AddStep (WizardStep newStep)
     {
-        SizeStep (newStep);
-
-        newStep.EnabledChanged += (s, e) => UpdateButtonsAndTitle ();
-        newStep.TitleChanged += (s, e) => UpdateButtonsAndTitle ();
+        newStep.EnabledChanged += (_, _) => UpdateButtonsAndTitle ();
+        newStep.TitleChanged += (_, _) => UpdateButtonsAndTitle ();
         _steps.AddLast (newStep);
         Add (newStep);
+
+        // Find the step's natural size
+        //newStep.SuperViewRendersLineCanvas = true;
+        newStep.Width = Dim.Auto ();
+        newStep.Height = Dim.Auto ();
+        newStep.SetRelativeLayout (App?.Screen.Size ?? new Size (2048, 2048));
+        newStep.LayoutSubViews ();
+
+        _maxStepSize = new (
+                            Math.Max (_maxStepSize.Width, newStep.Frame.Width),
+                            Math.Max (_maxStepSize.Height, newStep.Frame.Height));
+        newStep.Width = Dim.Fill ();
+        newStep.Height = Dim.Fill ();
+
+        newStep.SetRelativeLayout (App?.Screen.Size ?? new Size (2048, 2048));
+        newStep.LayoutSubViews ();
+        Width = Dim.Auto (minimumContentDim: _maxStepSize.Width + 2);
+        Height = Dim.Auto (minimumContentDim: _maxStepSize.Height + NextFinishButton.Frame.Height);
+
         UpdateButtonsAndTitle ();
     }
 
-    /// <summary>
-    ///     Raised when the user has cancelled the <see cref="Wizard"/> by pressing the Esc key. To prevent a modal (
-    ///     <see cref="WizardButtonEventArgs.Cancel"/> to <c>true</c> before returning from the event handler.
-    /// </summary>
-    public event EventHandler<WizardButtonEventArgs>? Cancelled;
-
-    /// <summary>
-    ///     Raised when the Next/Finish button in the <see cref="Wizard"/> is clicked. The Next/Finish button is always
-    ///     the last button in the array of Buttons passed to the <see cref="Wizard"/> constructor, if any. This event is only
-    ///     raised if the <see cref="CurrentStep"/> is the last Step in the Wizard flow (otherwise the <see cref="Finished"/>
-    ///     event is raised).
-    /// </summary>
-    public event EventHandler<WizardButtonEventArgs>? Finished;
+    /// <summary>Raised when the user cancels the wizard by pressing the Esc key.</summary>
+    public event EventHandler<CancelEventArgs>? Cancelled;
 
-    /// <summary>Returns the first enabled step in the Wizard</summary>
-    /// <returns>The last enabled step</returns>
+    /// <summary>Returns the first enabled step.</summary>
     public WizardStep? GetFirstStep () { return _steps.FirstOrDefault (s => s.Enabled); }
 
-    /// <summary>Returns the last enabled step in the Wizard</summary>
-    /// <returns>The last enabled step</returns>
+    /// <summary>Returns the last enabled step.</summary>
     public WizardStep? GetLastStep () { return _steps.LastOrDefault (s => s.Enabled); }
 
     /// <summary>
-    ///     Returns the next enabled <see cref="WizardStep"/> after the current step. Takes into account steps which are
-    ///     disabled. If <see cref="CurrentStep"/> is <c>null</c> returns the first enabled step.
+    ///     Returns the next enabled step after <see cref="CurrentStep"/>, skipping disabled steps.
     /// </summary>
-    /// <returns>
-    ///     The next step after the current step, if there is one; otherwise returns <c>null</c>, which indicates either
-    ///     there are no enabled steps or the current step is the last enabled step.
-    /// </returns>
+    /// <returns>The next enabled step, or <c>null</c> if none exists.</returns>
     public WizardStep? GetNextStep ()
     {
-        LinkedListNode<WizardStep>? step = null;
+        LinkedListNode<WizardStep>? step;
 
         if (CurrentStep is null)
         {
@@ -223,11 +227,7 @@ public class Wizard : Dialog
         {
             // Get the step after current
             step = _steps.Find (CurrentStep);
-
-            if (step is { })
-            {
-                step = step.Next;
-            }
+            step = step?.Next;
         }
 
         // step now points to the potential next step
@@ -245,16 +245,12 @@ public class Wizard : Dialog
     }
 
     /// <summary>
-    ///     Returns the first enabled <see cref="WizardStep"/> before the current step. Takes into account steps which are
-    ///     disabled. If <see cref="CurrentStep"/> is <c>null</c> returns the last enabled step.
+    ///     Returns the previous enabled step before <see cref="CurrentStep"/>, skipping disabled steps.
     /// </summary>
-    /// <returns>
-    ///     The first step ahead of the current step, if there is one; otherwise returns <c>null</c>, which indicates
-    ///     either there are no enabled steps or the current step is the first enabled step.
-    /// </returns>
+    /// <returns>The previous enabled step, or <c>null</c> if none exists.</returns>
     public WizardStep? GetPreviousStep ()
     {
-        LinkedListNode<WizardStep>? step = null;
+        LinkedListNode<WizardStep>? step;
 
         if (CurrentStep is null)
         {
@@ -265,11 +261,7 @@ public class Wizard : Dialog
         {
             // Get the step before current
             step = _steps.Find (CurrentStep);
-
-            if (step is { })
-            {
-                step = step.Previous;
-            }
+            step = step?.Previous;
         }
 
         // step now points to the potential previous step
@@ -286,188 +278,112 @@ public class Wizard : Dialog
         return null;
     }
 
-    /// <summary>
-    ///     Causes the wizard to move to the previous enabled step (or first step if <see cref="CurrentStep"/> is not set).
-    ///     If there is no previous step, does nothing.
-    /// </summary>
-    /// <returns><see langword="true"/> if the transition to the step succeeded. <see langword="false"/> if the step was not found or the operation was cancelled.</returns>
+    /// <summary>Navigates to the previous enabled step.</summary>
+    /// <returns><see langword="true"/> if the transition succeeded; otherwise <see langword="false"/>.</returns>
     public bool GoBack ()
     {
         WizardStep? previous = GetPreviousStep ();
 
-        if (previous is { })
-        {
-            return GoToStep (previous);
-        }
-
-        return false;
+        return previous is { } && GoToStep (previous);
     }
 
-    /// <summary>
-    ///     Causes the wizard to move to the next enabled step (or last step if <see cref="CurrentStep"/> is not set). If
-    ///     there is no previous step, does nothing.
-    /// </summary>
-    /// <returns><see langword="true"/> if the transition to the step succeeded. <see langword="false"/> if the step was not found or the operation was cancelled.</returns>
+    /// <summary>Navigates to the next enabled step.</summary>
+    /// <returns><see langword="true"/> if the transition succeeded; otherwise <see langword="false"/>.</returns>
     public bool GoNext ()
     {
         WizardStep? nextStep = GetNextStep ();
 
-        if (nextStep is { })
-        {
-            return GoToStep (nextStep);
-        }
-
-        return false;
-    }
-
-    /// <summary>Changes to the specified <see cref="WizardStep"/>.</summary>
-    /// <param name="newStep">The step to go to.</param>
-    /// <returns><see langword="true"/> if the transition to the step succeeded. <see langword="false"/> if the step was not found or the operation was cancelled.</returns>
-    public bool GoToStep (WizardStep? newStep)
-    {
-        if (OnStepChanging (_currentStep, newStep) || newStep is { Enabled: false })
-        {
-            return false;
-        }
-
-        // Hide all but the new step
-        foreach (WizardStep step in _steps)
-        {
-            step.Visible = step == newStep;
-            step.ShowHide ();
-        }
-
-        WizardStep? oldStep = _currentStep;
-        _currentStep = newStep;
-
-        UpdateButtonsAndTitle ();
-
-        // Set focus on the contentview
-        newStep?.SubViews.ToArray () [0].SetFocus ();
-
-        if (OnStepChanged (oldStep, _currentStep))
-        {
-            // For correctness, we do this, but it's meaningless because there's nothing to cancel
-            return false;
-        }
-
-        return true;
+        return nextStep is { } && GoToStep (nextStep);
     }
 
     /// <summary>
-    ///     Raised when the Back button in the <see cref="Wizard"/> is clicked. The Back button is always the first button
-    ///     in the array of Buttons passed to the <see cref="Wizard"/> constructor, if any.
-    /// </summary>
-    public event EventHandler<WizardButtonEventArgs>? MovingBack;
-
-    /// <summary>
-    ///     Raised when the Next/Finish button in the <see cref="Wizard"/> is clicked (or the user presses Enter). The
-    ///     Next/Finish button is always the last button in the array of Buttons passed to the <see cref="Wizard"/>
-    ///     constructor, if any. This event is only raised if the <see cref="CurrentStep"/> is the last Step in the Wizard flow
-    ///     (otherwise the <see cref="Finished"/> event is raised).
+    ///     Raised when the user clicks the Back button. Cancel to prevent navigation.
     /// </summary>
-    public event EventHandler<WizardButtonEventArgs>? MovingNext;
+    public event EventHandler<CancelEventArgs>? MovingBack;
 
     /// <summary>
-    ///     <see cref="Wizard"/> is derived from <see cref="Dialog"/> and Dialog causes <c>Esc</c> to call
-    ///     <see cref="IApplication.RequestStop(IRunnable)"/>, closing the Dialog. Wizard overrides
-    ///     <see cref="OnKeyDownNotHandled"/> to instead fire the <see cref="Cancelled"/> event when Wizard is being used as a
-    ///     non-modal.
+    ///     Raised when the user clicks Next on a non-final step. Cancel to prevent navigation.
     /// </summary>
-    /// <param name="key"></param>
-    /// <returns></returns>
-    protected override bool OnKeyDownNotHandled (Key key)
-    {
-        // BUGBUG: Why is this not handled by a key binding???
-        if (!IsModal)
-        {
-            if (key == Key.Esc)
-            {
-                var args = new WizardButtonEventArgs ();
-                Cancelled?.Invoke (this, args);
-
-                return false;
-            }
-        }
+    public event EventHandler<CancelEventArgs>? MovingNext;
 
-        return false;
-    }
-
-    /// <summary>
-    ///     Called when the <see cref="Wizard"/> has completed transition to a new <see cref="WizardStep"/>. Fires the
-    ///     <see cref="StepChanged"/> event.
-    /// </summary>
-    /// <param name="oldStep">The step the Wizard changed from</param>
-    /// <param name="newStep">The step the Wizard has changed to</param>
-    /// <returns>True if the change is to be cancelled.</returns>
-    public virtual bool OnStepChanged (WizardStep? oldStep, WizardStep? newStep)
+    /// <summary>Navigates to the specified step.</summary>
+    /// <param name="newStep">The step to navigate to.</param>
+    /// <returns><see langword="true"/> if the transition succeeded; otherwise <see langword="false"/>.</returns>
+    public bool GoToStep (WizardStep? newStep)
     {
-        var args = new StepChangeEventArgs (oldStep, newStep);
-        StepChanged?.Invoke (this, args);
-
-        return args.Cancel;
+        return CWPPropertyHelper.ChangeProperty (
+                                                 this,
+                                                 ref _currentStep,
+                                                 newStep,
+                                                 OnStepChanging,
+                                                 StepChanging,
+                                                 newValue =>
+                                                 {
+                                                     ValueChangingEventArgs<WizardStep?> args = new (_currentStep, newValue);
+                                                     StepChanging?.Invoke (this, args);
+
+                                                     if (args.Handled)
+                                                     {
+                                                         return;
+                                                     }
+
+                                                     // Hide all but the new step
+                                                     foreach (WizardStep step in _steps)
+                                                     {
+                                                         step.Visible = step == newValue;
+
+                                                         step.ShowHide ();
+                                                     }
+
+                                                     _currentStep = newValue;
+                                                     UpdateButtonsAndTitle ();
+                                                 },
+                                                 OnStepChanged,
+                                                 StepChanged,
+                                                 out _);
     }
 
-    /// <summary>
-    ///     Called when the <see cref="Wizard"/> is about to transition to another <see cref="WizardStep"/>. Fires the
-    ///     <see cref="StepChanging"/> event.
-    /// </summary>
-    /// <param name="oldStep">The step the Wizard is about to change from</param>
-    /// <param name="newStep">The step the Wizard is about to change to</param>
-    /// <returns>True if the change is to be cancelled.</returns>
-    public virtual bool OnStepChanging (WizardStep? oldStep, WizardStep? newStep)
-    {
-        var args = new StepChangeEventArgs (oldStep, newStep);
-        StepChanging?.Invoke (this, args);
+    /// <summary>Called before changing steps. Raises <see cref="StepChanging"/>.</summary>
+    /// <returns><see langword="true"/> to cancel the change.</returns>
+    protected virtual bool OnStepChanging (ValueChangingEventArgs<WizardStep?> args) => false;
 
-        return args.Cancel;
-    }
+    /// <summary>Raised before <see cref="CurrentStep"/> changes. Set <c>Handled</c> to cancel.</summary>
+    public event EventHandler<ValueChangingEventArgs<WizardStep?>>? StepChanging;
 
-    /// <summary>This event is raised after the <see cref="Wizard"/> has changed the <see cref="CurrentStep"/>.</summary>
-    public event EventHandler<StepChangeEventArgs>? StepChanged;
+    /// <summary>Called after changing steps. Raises <see cref="StepChanged"/>.</summary>
+    protected virtual void OnStepChanged (ValueChangedEventArgs<WizardStep?> args) { }
 
-    /// <summary>
-    ///     This event is raised when the current <see cref="CurrentStep"/>) is about to change. Use
-    ///     <see cref="StepChangeEventArgs.Cancel"/> to abort the transition.
-    /// </summary>
-    public event EventHandler<StepChangeEventArgs>? StepChanging;
+    /// <summary>Raised after <see cref="CurrentStep"/> changes.</summary>
+    public event EventHandler<ValueChangedEventArgs<WizardStep?>>? StepChanged;
 
-    private void BackBtn_Accepting (object? sender, CommandEventArgs e)
+    private void BackBtnOnAccepting (object? sender, CommandEventArgs e)
     {
-        var args = new WizardButtonEventArgs ();
+        CancelEventArgs args = new ();
         MovingBack?.Invoke (this, args);
 
-        if (!args.Cancel)
+        if (args.Cancel)
         {
-            e.Handled = GoBack ();
+            return;
         }
+
+        e.Handled = true;
+        GoBack ();
     }
 
-    private void NextFinishBtn_Accepting (object? sender, CommandEventArgs e)
+    private void NextFinishBtnOnAccepting (object? sender, CommandEventArgs e)
     {
         if (CurrentStep == GetLastStep ())
         {
-            var args = new WizardButtonEventArgs ();
-            Finished?.Invoke (this, args);
-
-            if (!args.Cancel)
+            if (RaiseAccepting (e.Context) is false)
             {
-                _finishedPressed = true;
-
-                if (IsCurrentTop)
-                {
-                    (sender as View)?.App?.RequestStop (this);
-                    e.Handled = true;
-                }
-
-                // Wizard was created as a non-modal (just added to another View). 
-                // Do nothing
+                e.Handled = true;
+                RequestStop ();
             }
         }
         else
         {
-            var args = new WizardButtonEventArgs ();
-            MovingNext?.Invoke (this, args);
+            CancelEventArgs args = new ();
+            MovingNext?.Invoke (this, new ());
 
             if (!args.Cancel)
             {
@@ -476,35 +392,6 @@ public class Wizard : Dialog
         }
     }
 
-    private void SizeStep (WizardStep step)
-    {
-        if (IsModal)
-        {
-            // If we're modal, then we expand the WizardStep so that the top and side 
-            // borders and not visible. The bottom border is the separator above the buttons.
-            step.X = step.Y = 0;
-
-            step.Height = Dim.Fill (
-                                    Dim.Func (
-                                              v => IsInitialized
-                                                        ? SubViews.First (view => view.Y.Has<PosAnchorEnd> (out _)).Frame.Height + 1
-                                                        : 1)); // for button frame (+1 for lineView)
-            step.Width = Dim.Fill ();
-        }
-        else
-        {
-            // If we're not a modal, then we show the border around the WizardStep
-            step.X = step.Y = 0;
-
-            step.Height = Dim.Fill (
-                                    Dim.Func (
-                                              v => IsInitialized
-                                                       ? SubViews.First (view => view.Y.Has<PosAnchorEnd> (out _)).Frame.Height + 1
-                                                       : 2)); // for button frame (+1 for lineView)
-            step.Width = Dim.Fill ();
-        }
-    }
-
     private void UpdateButtonsAndTitle ()
     {
         if (CurrentStep is null)
@@ -533,35 +420,64 @@ public class Wizard : Dialog
                                         ? CurrentStep.NextButtonText
                                         : Strings.wzNext; // "_Next...";
         }
-
-        SizeStep (CurrentStep);
-
-        SetNeedsLayout ();
     }
 
-    private void Wizard_IsRunningChanged (object? sender, EventArgs<bool> args)
+    bool IDesignable.EnableForDesign ()
     {
-        if (!_finishedPressed)
+        Title = "Wizard Title";
+
+        WizardStep firstStep = new ();
+        (firstStep as IDesignable).EnableForDesign ();
+        AddStep (firstStep);
+
+        Label schemeLabel = new ()
         {
-            var a = new WizardButtonEventArgs ();
-            Cancelled?.Invoke (this, a);
-        }
-    }
+            Title = "_Scheme:"
+        };
 
-    private void Wizard_IsModalChanged (object? sender, EventArgs<bool> args)
-    {
-        if (args.Value)
+        OptionSelector<Schemes> selector = new ()
         {
-            CurrentStep = GetFirstStep ();
-            // gets the first step if CurrentStep == null
-        }
-    }
+            X = Pos.Right (schemeLabel) + 1,
+            Title = "Select Scheme"
+        };
 
-    private void Wizard_TitleChanged (object? sender, EventArgs<string> e)
-    {
-        if (string.IsNullOrEmpty (_wizardTitle))
+        selector.ValueChanged += (_, _) =>
+                                 {
+                                     if (selector.Value is { } scheme)
+                                     {
+                                         SchemeName = SchemeManager.SchemesToSchemeName (scheme);
+                                     }
+                                 };
+
+        Label borderStyleLabel = new ()
         {
-            _wizardTitle = e.Value;
-        }
+            Title = "_Border Style:",
+            X = Pos.Right (selector) + 2
+        };
+
+        OptionSelector<LineStyle> borderStyleSelector = new ()
+        {
+            X = Pos.Right (borderStyleLabel) + 1,
+            Title = "Select Border Style"
+        };
+
+        borderStyleSelector.ValueChanged += (_, _) =>
+                                            {
+                                                if (borderStyleSelector.Value is { } style)
+                                                {
+                                                    BorderStyle = style;
+                                                }
+                                            };
+
+        WizardStep secondStep = new ()
+        {
+            Title = "Second Step",
+            HelpText = "This is the help text for the Second Step."
+        };
+        secondStep.Add (schemeLabel, selector, borderStyleLabel, borderStyleSelector);
+
+        AddStep (secondStep);
+
+        return true;
     }
 }

+ 0 - 35
Terminal.Gui/Views/Wizard/WizardEventArgs.cs

@@ -1,35 +0,0 @@
-#nullable disable
-namespace Terminal.Gui.Views;
-
-/// <summary><see cref="EventArgs"/> for <see cref="WizardStep"/> transition events.</summary>
-public class WizardButtonEventArgs : EventArgs
-{
-    /// <summary>Initializes a new instance of <see cref="WizardButtonEventArgs"/></summary>
-    public WizardButtonEventArgs () { Cancel = false; }
-
-    /// <summary>Set to true to cancel the transition to the next step.</summary>
-    public bool Cancel { get; set; }
-}
-
-/// <summary><see cref="EventArgs"/> for <see cref="WizardStep"/> events.</summary>
-public class StepChangeEventArgs : EventArgs
-{
-    /// <summary>Initializes a new instance of <see cref="StepChangeEventArgs"/></summary>
-    /// <param name="oldStep">The current <see cref="WizardStep"/>.</param>
-    /// <param name="newStep">The new <see cref="WizardStep"/>.</param>
-    public StepChangeEventArgs (WizardStep oldStep, WizardStep newStep)
-    {
-        OldStep = oldStep;
-        NewStep = newStep;
-        Cancel = false;
-    }
-
-    /// <summary>Event handlers can set to true before returning to cancel the step transition.</summary>
-    public bool Cancel { get; set; }
-
-    /// <summary>The <see cref="WizardStep"/> the <see cref="Wizard"/> is changing to or has changed to.</summary>
-    public WizardStep NewStep { get; }
-
-    /// <summary>The current (or previous) <see cref="WizardStep"/>.</summary>
-    public WizardStep OldStep { get; }
-}

+ 104 - 141
Terminal.Gui/Views/Wizard/WizardStep.cs

@@ -1,29 +1,16 @@
-
-
 namespace Terminal.Gui.Views;
 
 /// <summary>
-///     Represents a basic step that is displayed in a <see cref="Wizard"/>. The <see cref="WizardStep"/> view is
-///     divided horizontally in two. On the left is the content view where <see cref="View"/>s can be added,  On the right
-///     is the help for the step. Set <see cref="WizardStep.HelpText"/> to set the help text. If the help text is empty the
-///     help pane will not be shown. If there are no Views added to the WizardStep the <see cref="HelpText"/> (if not
-///     empty) will fill the wizard step.
+///     A single step in a <see cref="Wizard"/>. Can contain arbitrary <see cref="View"/>s and display help text
+///     in the right <see cref="Padding"/>.
 /// </summary>
 /// <remarks>
-///     If <see cref="Button"/>s are added, do not set <see cref="Button.IsDefault"/> to true as this will conflict
-///     with the Next button of the Wizard. Subscribe to the <see cref="View.VisibleChanged"/> event to be notified when
-///     the step is active; see also: <see cref="Wizard.StepChanged"/>. To enable or disable a step from being shown to the
-///     user, set <see cref="View.Enabled"/>.
+///     Do not set <see cref="Button.IsDefault"/> on added buttons (conflicts with Wizard navigation).
+///     Use <see cref="View.VisibleChanged"/> or <see cref="Wizard.StepChanged"/> to detect when this step becomes active.
+///     Set <see cref="View.Enabled"/> to control whether the step is shown.
 /// </remarks>
-public class WizardStep : View
+public class WizardStep : View, IDesignable
 {
-    // The contentView works like the ContentView in FrameView.
-    private readonly View _contentView = new ()
-    {
-        CanFocus = true,
-        TabStop = TabBehavior.TabStop,
-        Id = "WizardStep._contentView"
-    };
     private readonly TextView _helpTextView = new ()
     {
         CanFocus = true,
@@ -31,78 +18,61 @@ public class WizardStep : View
         ReadOnly = true,
         WordWrap = true,
         AllowsTab = false,
+        X = Pos.AnchorEnd () + 1,
+        Height = Dim.Fill (),
+#if DEBUG
         Id = "WizardStep._helpTextView"
+#endif
     };
 
     /// <summary>
-    ///     Initializes a new instance of the <see cref="Wizard"/> class.
+    ///     Initializes a new instance of the <see cref="WizardStep"/> class.
     /// </summary>
     public WizardStep ()
     {
         TabStop = TabBehavior.TabStop;
         CanFocus = true;
-        BorderStyle = LineStyle.None;
-
-        base.Add (_contentView);
-
-        base.Add (_helpTextView);
-
-        // BUGBUG: v2 - Disabling scrolling for now
-        //var scrollBar = new ScrollBarView (helpTextView, true);
-
-        //scrollBar.ChangedPosition += (s,e) => {
-        //	helpTextView.TopRow = scrollBar.Position;
-        //	if (helpTextView.TopRow != scrollBar.Position) {
-        //		scrollBar.Position = helpTextView.TopRow;
-        //	}
-        //	helpTextView.SetNeedsDraw ();
-        //};
-
-        //scrollBar.OtherScrollBarView.ChangedPosition += (s,e) => {
-        //	helpTextView.LeftColumn = scrollBar.OtherScrollBarView.Position;
-        //	if (helpTextView.LeftColumn != scrollBar.OtherScrollBarView.Position) {
-        //		scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn;
-        //	}
-        //	helpTextView.SetNeedsDraw ();
-        //};
-
-        //scrollBar.VisibleChanged += (s,e) => {
-        //	if (scrollBar.Visible && helpTextView.RightOffset == 0) {
-        //		helpTextView.RightOffset = 1;
-        //	} else if (!scrollBar.Visible && helpTextView.RightOffset == 1) {
-        //		helpTextView.RightOffset = 0;
-        //	}
-        //};
-
-        //scrollBar.OtherScrollBarView.VisibleChanged += (s,e) => {
-        //	if (scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 0) {
-        //		helpTextView.BottomOffset = 1;
-        //	} else if (!scrollBar.OtherScrollBarView.Visible && helpTextView.BottomOffset == 1) {
-        //		helpTextView.BottomOffset = 0;
-        //	}
-        //};
-
-        //helpTextView.DrawContent += (s,e) => {
-        //	scrollBar.Size = helpTextView.Lines;
-        //	scrollBar.Position = helpTextView.TopRow;
-        //	if (scrollBar.OtherScrollBarView is { }) {
-        //		scrollBar.OtherScrollBarView.Size = helpTextView.Maxlength;
-        //		scrollBar.OtherScrollBarView.Position = helpTextView.LeftColumn;
-        //	}
-        //	scrollBar.LayoutSubViews ();
-        //	scrollBar.Refresh ();
-        //};
-        //base.Add (scrollBar);
+        Width = Dim.Fill ();
+        Height = Dim.Fill ();
+    }
+
+    /// <inheritdoc/>
+    public override void EndInit ()
+    {
+        // Help text goes in the right Padding
+        // TODO: Enable built-in scrollbars for the help text view once TextView supports
+        //_helpTextView.VerticalScrollBar.AutoShow = true;
+        //_helpTextView.HorizontalScrollBar.AutoShow = true;
+        _helpTextView.Width = Dim.Func (_ => CalculateHelpPaddingWidth ());
+
+        Padding?.Add (_helpTextView);
+
         ShowHide ();
+        base.EndInit ();
     }
 
-    /// <summary>Sets or gets the text for the back button. The back button will only be visible on steps after the first step.</summary>
-    /// <remarks>The default text is "Back"</remarks>
+    /// <summary>The text for the Back button. Defaults to "Back".</summary>
     public string BackButtonText { get; set; } = string.Empty;
 
+    /// <summary>Calculates the width for the help text padding based on the current frame width.</summary>
+    private int CalculateHelpPaddingWidth () => 25;
+
+    /// <inheritdoc/>
+    protected override void OnFrameChanged (in Rectangle frame)
+    {
+        base.OnFrameChanged (frame);
+
+        // Update padding thickness when frame changes
+        if (Padding is { } && _helpTextView.Text.Length > 0)
+        {
+            Padding.Thickness = Padding.Thickness with { Right = CalculateHelpPaddingWidth () };
+            App?.Invoke (() => Layout ());
+        }
+    }
+
     /// <summary>
-    ///     Sets or gets help text for the <see cref="WizardStep"/>.If <see cref="WizardStep.HelpText"/> is empty the help
-    ///     pane will not be visible and the content will fill the entire WizardStep.
+    ///     The help text displayed in the right <see cref="Padding"/>.
+    ///     If empty, the right padding is hidden and content fills the entire step.
     /// </summary>
     /// <remarks>The help text is displayed using a read-only <see cref="TextView"/>.</remarks>
     public string HelpText
@@ -111,98 +81,91 @@ public class WizardStep : View
         set
         {
             _helpTextView.Text = value;
+            _helpTextView.MoveHome ();
             ShowHide ();
-            SetNeedsDraw ();
         }
     }
 
-    /// <summary>Sets or gets the text for the next/finish button.</summary>
-    /// <remarks>The default text is "Next..." if the Pane is not the last pane. Otherwise it is "Finish"</remarks>
+    /// <summary>The text for the Next/Finish button. Defaults to "Next..." or "Finish" based on position.</summary>
     public string NextButtonText { get; set; } = string.Empty;
 
-    /// <summary>Add the specified <see cref="View"/> to the <see cref="WizardStep"/>.</summary>
-    /// <param name="view"><see cref="View"/> to add to this container</param>
-    public override View Add (View? view)
+    /// <summary>Does the work to show and hide the contentView and helpView as appropriate</summary>
+    internal void ShowHide ()
     {
-        _contentView.Add (view);
-
-        if (view!.CanFocus)
+        // Check if views are available (might be null during disposal)
+        if (Padding is null)
         {
-            CanFocus = true;
+            return;
         }
 
-        ShowHide ();
+        if (_helpTextView.Text.Length > 0)
+        {
+            // Configure Padding
 
-        return view;
-    }
+            Padding.CanFocus = true;
+            Padding.TabStop = TabBehavior.TabStop;
 
-    /// <summary>Removes a <see cref="View"/> from <see cref="WizardStep"/>.</summary>
-    /// <remarks></remarks>
-    public override View? Remove (View? view)
-    {
-        SetNeedsDraw ();
-        View? container = view?.SuperView;
+            // Help text goes in right Padding - set thickness based on current frame width
+            Padding.Thickness = Padding.Thickness with { Right = CalculateHelpPaddingWidth () };
 
-        if (container == this)
-        {
-            base.Remove (view);
+            _helpTextView.Visible = true;
+            _helpTextView.Enabled = true;
         }
         else
         {
-            container?.Remove (view);
-        }
+            // Configure Padding
 
-        if (_contentView.InternalSubViews.Count < 1)
-        {
-            CanFocus = false;
-        }
+            Padding.CanFocus = false;
 
-        ShowHide ();
+            // No help text - no right padding needed
+            Padding.Thickness = Padding.Thickness with { Right = 0 };
 
-        return view;
-    }
-
-    /// <summary>Removes all <see cref="View"/>s from the <see cref="WizardStep"/>.</summary>
-    /// <remarks></remarks>
-    public override IReadOnlyCollection<View> RemoveAll ()
-    {
-        IReadOnlyCollection<View> removed = _contentView.RemoveAll ();
-        ShowHide ();
+            _helpTextView.Visible = false;
+            _helpTextView.Enabled = false;
+        }
 
-        return removed;
+        SetNeedsLayout ();
     }
 
-    /// <summary>Does the work to show and hide the contentView and helpView as appropriate</summary>
-    internal void ShowHide ()
+    bool IDesignable.EnableForDesign ()
     {
-        _contentView.Height = Dim.Fill ();
-        _helpTextView.Height = Dim.Height(_contentView);
-        _helpTextView.Width = Dim.Fill ();
+        Title = "Example Step";
 
-        if (_contentView.InternalSubViews?.Count > 0)
+        Label label = new ()
         {
-            if (_helpTextView.Text.Length > 0)
-            {
-                _contentView.Width = Dim.Percent (70);
-                _helpTextView.X = Pos.Right (_contentView);
-                _helpTextView.Width = Dim.Fill ();
-            }
-            else
-            {
-                _contentView.Width = Dim.Fill ();
-            }
-        }
-        else
+            Title = "_Enter Text:"
+        };
+
+        TextField textField = new ()
         {
-            if (_helpTextView.Text.Length > 0)
-            {
-                _helpTextView.X = 0;
-            }
+            X = Pos.Right (label) + 1,
+            Width = 20
+        };
+        Add (label, textField);
 
-            // Error - no pane shown
-        }
+        label = new ()
+        {
+            Title = "    _A List:",
+            Y = Pos.Bottom (label) + 1
+        };
 
-        _contentView.Visible = _contentView.InternalSubViews?.Count > 0;
-        _helpTextView.Visible = _helpTextView.Text.Length > 0;
+        ListView listView = new ()
+        {
+            BorderStyle = LineStyle.Dashed,
+            X = Pos.Right (label) + 1,
+            Y = Pos.Top (label),
+            Height = Dim.Auto (),
+            Width = 10,
+            Source = new ListWrapper<string> (["Item 1", "Item 2", "Item 3", "Item 4", "Item 5"]),
+            SelectedItem = 0
+        };
+        Add (label, listView);
+
+        HelpText = """
+                   This is some help text for the WizardStep. 
+                   You can provide instructions or information to guide the user through this step of the wizard.
+                   """;
+
+        return true;
     }
 } // end of WizardStep class

+ 4 - 1
Terminal.sln.DotSettings

@@ -14,7 +14,7 @@
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeMissingParentheses/@EntryIndexedValue">SUGGESTION</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeModifiersOrder/@EntryIndexedValue">WARNING</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeNamespaceBody/@EntryIndexedValue">ERROR</s:String>
-	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeNullCheckingPattern/@EntryIndexedValue">ERROR</s:String>
+	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeNullCheckingPattern/@EntryIndexedValue">DO_NOT_SHOW</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeObjectCreationWhenTypeEvident/@EntryIndexedValue">WARNING</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeObjectCreationWhenTypeNotEvident/@EntryIndexedValue">SUGGESTION</s:String>
 	<s:String x:Key="/Default/CodeInspection/Highlighting/InspectionSeverities/=ArrangeRedundantParentheses/@EntryIndexedValue">WARNING</s:String>
@@ -414,12 +414,15 @@
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EMigrateBlankLinesAroundFieldToBlankLinesAroundProperty/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/Environment/SettingsMigration/IsMigratorApplied/=JetBrains_002EReSharper_002EPsi_002ECSharp_002ECodeStyle_002ESettingsUpgrade_002EPredefinedNamingRulesToUserRulesUpgrade/@EntryIndexedValue">True</s:Boolean>
 	<s:Int64 x:Key="/Default/Environment/UnitTesting/ParallelProcessesCount/@EntryValue">5</s:Int64>
+	<s:Boolean x:Key="/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=app_002ERun/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/GrammarAndSpelling/GrammarChecking/Exceptions/=Attribute_0020attribute/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=conhost/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Decscusr/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/UserDictionary/Words/=Depeche/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=diag/@EntryIndexedValue">True</s:Boolean>
 	
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Gainsboro/@EntryIndexedValue">True</s:Boolean>
+	<s:Boolean x:Key="/Default/UserDictionary/Words/=Gandolf/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Gonek/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=Guppie/@EntryIndexedValue">True</s:Boolean>
 	<s:Boolean x:Key="/Default/UserDictionary/Words/=IDISPOSABLE/@EntryIndexedValue">True</s:Boolean>

+ 4 - 4
Tests/UnitTests/Dialogs/WizardTests.cs

@@ -22,7 +22,7 @@ public class WizardTests
         wizard.AddStep (step1);
 
         var finishedFired = false;
-        wizard.Finished += (s, args) => { finishedFired = true; };
+        wizard.Accepting += (s, args) => { finishedFired = true; };
 
         var isRunningChangedFired = false;
         wizard.IsRunningChanged += (s, e) => { isRunningChangedFired = true; };
@@ -46,7 +46,7 @@ public class WizardTests
         wizard.AddStep (step2);
 
         finishedFired = false;
-        wizard.Finished += (s, args) => { finishedFired = true; };
+        wizard.Accepting += (s, args) => { finishedFired = true; };
 
         isRunningChangedFired = false;
         wizard.IsRunningChanged += (s, e) => { isRunningChangedFired = true; };
@@ -79,7 +79,7 @@ public class WizardTests
         step1.Enabled = false;
 
         finishedFired = false;
-        wizard.Finished += (s, args) => { finishedFired = true; };
+        wizard.Accepting += (s, args) => { finishedFired = true; };
 
         isRunningChangedFired = false;
         wizard.IsRunningChanged += (s, e) => { isRunningChangedFired = true; };
@@ -437,7 +437,7 @@ public class WizardTests
     // this test is needed because Wizard overrides Dialog's title behavior ("Title - StepTitle")
     public void Setting_Title_Works ()
     {
-        var d = Application.Driver;
+        IDriver d = Application.Driver;
 
         var title = "1234";
         var stepTitle = " - ABCD";

+ 97 - 14
Tests/UnitTestsParallelizable/ViewBase/Adornment/AdornmentSubViewTests.cs

@@ -1,21 +1,24 @@
-using Xunit.Abstractions;
+using UnitTests;
+using Xunit.Abstractions;
 
 namespace ViewBaseTests.Adornments;
 
-public class AdornmentSubViewTests ()
+public class AdornmentSubViewTests (ITestOutputHelper output)
 {
+    private readonly ITestOutputHelper _output = output;
+
     [Fact]
     public void Setting_Thickness_Causes_Adornment_SubView_Layout ()
     {
         var view = new View ();
         var subView = new View ();
-        view.Margin!.Add (subView);
+        view.Padding!.Add (subView);
         view.BeginInit ();
         view.EndInit ();
         var raised = false;
 
         subView.SubViewLayout += LayoutStarted;
-        view.Margin.Thickness = new Thickness (1, 2, 3, 4);
+        view.Padding.Thickness = new (1, 2, 3, 4);
         view.Layout ();
         Assert.True (raised);
 
@@ -27,12 +30,12 @@ public class AdornmentSubViewTests ()
     }
 
     [Theory]
-    [InlineData (0, 0, false)] // Margin has no thickness, so false
-    [InlineData (0, 1, false)] // Margin has no thickness, so false
+    [InlineData (0, 0, false)] // Padding has no thickness, so false
+    [InlineData (0, 1, false)] // Padding has no thickness, so false
     [InlineData (1, 0, true)]
     [InlineData (1, 1, true)]
     [InlineData (2, 1, true)]
-    public void Adornment_WithSubView_Finds (int viewMargin, int subViewMargin, bool expectedFound)
+    public void Adornment_WithSubView_Finds (int viewPadding, int subViewPadding, bool expectedFound)
     {
         IApplication? app = Application.Create ();
         Runnable<bool> runnable = new ()
@@ -42,9 +45,9 @@ public class AdornmentSubViewTests ()
         };
         app.Begin (runnable);
 
-        runnable.Margin!.Thickness = new Thickness (viewMargin);
+        runnable.Padding!.Thickness = new (viewPadding);
         // Turn of TransparentMouse for the test
-        runnable.Margin!.ViewportSettings = ViewportSettingsFlags.None;
+        runnable.Padding!.ViewportSettings = ViewportSettingsFlags.None;
 
         var subView = new View ()
         {
@@ -53,16 +56,16 @@ public class AdornmentSubViewTests ()
             Width = 5,
             Height = 5
         };
-        subView.Margin!.Thickness = new Thickness (subViewMargin);
+        subView.Padding!.Thickness = new (subViewPadding);
         // Turn of TransparentMouse for the test
-        subView.Margin!.ViewportSettings = ViewportSettingsFlags.None;
+        subView.Padding!.ViewportSettings = ViewportSettingsFlags.None;
 
-        runnable.Margin!.Add (subView);
+        runnable.Padding!.Add (subView);
         runnable.Layout ();
 
-        var foundView = runnable.GetViewsUnderLocation (new Point (0, 0), ViewportSettingsFlags.None).LastOrDefault ();
+        View? foundView = runnable.GetViewsUnderLocation (new (0, 0), ViewportSettingsFlags.None).LastOrDefault ();
 
-        bool found = foundView == subView || foundView == subView.Margin;
+        bool found = foundView == subView || foundView == subView.Padding;
         Assert.Equal (expectedFound, found);
     }
 
@@ -92,4 +95,84 @@ public class AdornmentSubViewTests ()
         Assert.Equal (runnable.Padding, runnable.GetViewsUnderLocation (new Point (0, 0), ViewportSettingsFlags.None).LastOrDefault ());
 
     }
+    
+    [Fact]
+    public void Button_With_Opaque_ShadowStyle_In_Border_Should_Draw_Shadow ()
+    {
+        // Arrange
+        using IApplication app = Application.Create ();
+        app.Init ("fake");
+        app.Driver?.SetScreenSize (1, 4);
+        app.Driver!.Force16Colors = true;
+
+        using Runnable window = new ();
+        window.Width = Dim.Fill ();
+        window.Height = Dim.Fill ();
+        window.Text = @"XXXXXX";
+        window.SetScheme (new (new Attribute (Color.Black, Color.White)));
+
+        // Setup padding with some thickness so we have space for the button
+        window.Border!.Thickness = new (0, 3, 0, 0);
+
+        // Add a button with a transparent shadow to the Padding adornment
+        Button buttonInBorder = new ()
+        {
+            X = 0,
+            Y = 0,
+            Text = "B",
+            NoDecorations = true,
+            NoPadding = true,
+            ShadowStyle = ShadowStyle.Opaque,
+        };
+
+        window.Border.Add (buttonInBorder);
+        app.Begin (window);
+
+        DriverAssert.AssertDriverOutputIs ("""
+                                           \x1b[30m\x1b[107mB▝ \x1b[97m\x1b[40mX
+                                           """,
+                                           _output,
+                                           app.Driver);
+    }
+
+    [Fact]
+    public void Button_With_Opaque_ShadowStyle_In_Padding_Should_Draw_Shadow ()
+    {
+        // Arrange
+        using IApplication app = Application.Create ();
+        app.Init ("fake");
+        app.Driver?.SetScreenSize (1, 4);
+        app.Driver!.Force16Colors = true;
+
+        using Runnable window = new ();
+        window.Width = Dim.Fill ();
+        window.Height = Dim.Fill ();
+        window.Text = @"XXXXXX";
+        window.SetScheme (new (new Attribute (Color.Black, Color.White)));
+
+        // Setup padding with some thickness so we have space for the button
+        window.Padding!.Thickness = new (0, 3, 0, 0);
+
+        // Add a button with a transparent shadow to the Padding adornment
+        Button buttonInPadding = new ()
+        {
+            X = 0,
+            Y = 0,
+            Text = "B",
+            NoDecorations = true,
+            NoPadding = true,
+            ShadowStyle = ShadowStyle.Opaque,
+        };
+
+        window.Padding.Add (buttonInPadding);
+        app.Begin (window);
+
+        DriverAssert.AssertDriverOutputIs ("""
+                                           \x1b[97m\x1b[40mB\x1b[30m\x1b[107m▝ \x1b[97m\x1b[40mX
+                                           """,
+                                           _output,
+                                           app.Driver);
+    }
+
 }
+

+ 25 - 0
Tests/UnitTestsParallelizable/ViewBase/Adornment/PaddingTests.cs

@@ -0,0 +1,25 @@
+#nullable enable
+using UnitTests;
+using Xunit.Abstractions;
+
+namespace ViewBaseTests.Adornments;
+
+public class PaddingTests (ITestOutputHelper output)
+{
+    [Fact]
+    public void Constructor_Defaults ()
+    {
+        View view = new () { Height = 3, Width = 3 };
+        Assert.True (view.Padding!.CanFocus);
+        Assert.Equal (TabBehavior.NoStop, view.Padding.TabStop);
+        Assert.Empty (view.Padding!.KeyBindings.GetBindings ());
+    }
+
+    [Fact]
+    public void Thickness_Is_Empty_By_Default ()
+    {
+        View view = new () { Height = 3, Width = 3 };
+        Assert.Equal (Thickness.Empty, view.Padding!.Thickness);
+    }
+
+}

+ 0 - 2
Tests/UnitTestsParallelizable/ViewBase/Layout/GetViewsUnderLocationForRootTests.cs

@@ -210,7 +210,6 @@ public class GetViewsUnderLocationForRootTests
     }
 
     [Theory]
-    [InlineData ("Margin")]
     [InlineData ("Border")]
     [InlineData ("Padding")]
     public void Returns_Subview_Of_Adornment (string adornmentType)
@@ -271,7 +270,6 @@ public class GetViewsUnderLocationForRootTests
 
 
     [Theory]
-    [InlineData ("Margin")]
     [InlineData ("Border")]
     [InlineData ("Padding")]
     public void Returns_OnlyParentsSuperView_Of_Adornment_If_TransparentMouse (string adornmentType)

+ 586 - 0
Tests/UnitTestsParallelizable/ViewBase/Navigation/AdornmentNavigationTests.cs

@@ -0,0 +1,586 @@
+namespace ViewBaseTests.Navigation;
+
+/// <summary>
+/// Tests for navigation into and out of Adornments (Padding, Border, Margin).
+/// These tests prove that navigation to/from adornments is broken and need to be fixed.
+/// </summary>
+public class AdornmentNavigationTests
+{
+    #region Padding Navigation Tests
+
+    [Fact]
+    [Trait ("Category", "Adornment")]
+    [Trait ("Category", "Navigation")]
+    public void AdvanceFocus_Into_Padding_With_Focusable_SubView ()
+    {
+        // Setup: View with a focusable subview in Padding
+        View view = new ()
+        {
+            Id = "view",
+            Width = 10,
+            Height = 10,
+            CanFocus = true
+        };
+
+        view.Padding!.Thickness = new Thickness (1);
+
+        View paddingButton = new ()
+        {
+            Id = "paddingButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Padding.Add (paddingButton);
+
+        View contentButton = new ()
+        {
+            Id = "contentButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Add (contentButton);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // Test: Advance focus should navigate to content first
+        view.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+
+        // Expected: contentButton should have focus
+        // This test documents the expected behavior for navigation into padding
+        Assert.True (contentButton.HasFocus, "Content view should receive focus first");
+        Assert.False (paddingButton.HasFocus, "Padding subview should not have focus yet");
+
+        // Test: Advance focus again should go to padding
+        view.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+
+        // Expected: paddingButton should now have focus
+        // This will likely FAIL, proving the bug exists
+        Assert.True (paddingButton.HasFocus, "Padding subview should receive focus after content");
+        Assert.False (contentButton.HasFocus, "Content view should no longer have focus");
+
+        view.Dispose ();
+    }
+
+    [Fact]
+    [Trait ("Category", "Adornment")]
+    [Trait ("Category", "Navigation")]
+    public void AdvanceFocus_Out_Of_Padding_To_Content ()
+    {
+        // Setup: View with focusable padding that has focus
+        View view = new ()
+        {
+            Id = "view",
+            Width = 10,
+            Height = 10,
+            CanFocus = true
+        };
+
+        view.Padding!.Thickness = new Thickness (1);
+
+        View paddingButton = new ()
+        {
+            Id = "paddingButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Padding.Add (paddingButton);
+
+        View contentButton = new ()
+        {
+            Id = "contentButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Add (contentButton);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // Set focus to padding button
+        paddingButton.SetFocus ();
+        Assert.True (paddingButton.HasFocus, "Setup: Padding button should have focus");
+
+        // Test: Advance focus should navigate from padding to content
+        view.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+
+        // Expected: Should navigate to content
+        // This will likely FAIL, proving the bug exists
+        Assert.True (contentButton.HasFocus, "Content view should receive focus after padding");
+        Assert.False (paddingButton.HasFocus, "Padding button should no longer have focus");
+
+        view.Dispose ();
+    }
+
+    [Fact]
+    [Trait ("Category", "Adornment")]
+    [Trait ("Category", "Navigation")]
+    public void AdvanceFocus_Backward_Into_Padding ()
+    {
+        // Setup: View with focusable subviews in both content and padding
+        View view = new ()
+        {
+            Id = "view",
+            Width = 10,
+            Height = 10,
+            CanFocus = true
+        };
+
+        view.Padding!.Thickness = new Thickness (1);
+
+        View paddingButton = new ()
+        {
+            Id = "paddingButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Padding.Add (paddingButton);
+
+        View contentButton = new ()
+        {
+            Id = "contentButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Add (contentButton);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // Set focus to content
+        contentButton.SetFocus ();
+        Assert.True (contentButton.HasFocus, "Setup: Content button should have focus");
+
+        // Test: Advance focus backward should go to padding
+        view.AdvanceFocus (NavigationDirection.Backward, TabBehavior.TabStop);
+
+        // Expected: Should navigate to padding
+        // This will likely FAIL, proving the bug exists
+        Assert.True (paddingButton.HasFocus, "Padding button should receive focus when navigating backward");
+        Assert.False (contentButton.HasFocus, "Content button should no longer have focus");
+
+        view.Dispose ();
+    }
+
+    [Fact]
+    [Trait ("Category", "Adornment")]
+    [Trait ("Category", "Navigation")]
+    public void Padding_CanFocus_True_TabStop_TabStop_Should_Be_In_FocusChain ()
+    {
+        // Setup: View with focusable Padding
+        View view = new ()
+        {
+            Id = "view",
+            Width = 10,
+            Height = 10,
+            CanFocus = true
+        };
+
+        view.Padding!.Thickness = new (1);
+        view.Padding.CanFocus = true;
+        view.Padding.TabStop = TabBehavior.TabStop;
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // Test: Get focus chain
+        View [] focusChain = view.GetFocusChain (NavigationDirection.Forward, TabBehavior.TabStop);
+
+        // Expected: Padding should be in the focus chain
+        // This should pass based on the GetFocusChain code
+        Assert.Contains (view.Padding, focusChain);
+
+        view.Dispose ();
+    }
+
+    #endregion
+
+    #region Border Navigation Tests
+
+    [Fact]
+    [Trait ("Category", "Adornment")]
+    [Trait ("Category", "Navigation")]
+    public void AdvanceFocus_Into_Border_With_Focusable_SubView ()
+    {
+        // Setup: View with a focusable subview in Border
+        View view = new ()
+        {
+            Id = "view",
+            Width = 10,
+            Height = 10,
+            CanFocus = true
+        };
+
+        view.Border!.Thickness = new Thickness (1);
+
+        View borderButton = new ()
+        {
+            Id = "borderButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabGroup,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Border.Add (borderButton);
+
+        View contentButton = new ()
+        {
+            Id = "contentButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabGroup,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Add (contentButton);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // Test: Advance focus should navigate between content and border
+        view.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabGroup);
+
+        // Expected: One of them should have focus
+        var hasFocus = contentButton.HasFocus || borderButton.HasFocus;
+        Assert.True (hasFocus, "Either content or border button should have focus");
+
+        // Advance again
+        view.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabGroup);
+
+        // Expected: The other one should now have focus
+        // This will likely FAIL, proving the bug exists
+        if (contentButton.HasFocus)
+        {
+            // If content has focus now, border should have had it before
+            Assert.False (borderButton.HasFocus, "Only one should have focus at a time");
+        }
+        else
+        {
+            Assert.True (borderButton.HasFocus, "Border should have focus if content doesn't");
+        }
+
+        view.Dispose ();
+    }
+
+    [Fact]
+    [Trait ("Category", "Adornment")]
+    [Trait ("Category", "Navigation")]
+    public void Border_CanFocus_True_TabStop_TabGroup_Should_NOT_Be_In_FocusChain ()
+    {
+        // Setup: View with focusable Border (default TabStop is TabGroup for Border)
+        View view = new ()
+        {
+            Id = "view",
+            Width = 10,
+            Height = 10,
+            CanFocus = true
+        };
+
+        view.Border!.Thickness = new Thickness (1);
+        view.Border.CanFocus = true;
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // Test: Get focus chain for TabGroup
+        View [] focusChain = view.GetFocusChain (NavigationDirection.Forward, TabBehavior.TabGroup);
+
+        // Expected: Border should be in the focus chain
+        Assert.DoesNotContain (view.Border, focusChain);
+
+        view.Dispose ();
+    }
+
+    #endregion
+
+    #region Margin Navigation Tests
+
+    [Fact]
+    [Trait ("Category", "Adornment")]
+    [Trait ("Category", "Navigation")]
+    public void Margin_CanFocus_True_Should_NOT_Be_In_FocusChain ()
+    {
+        // Setup: View with focusable Margin
+        View view = new ()
+        {
+            Id = "view",
+            Width = 10,
+            Height = 10,
+            CanFocus = true
+        };
+
+        view.Margin!.Thickness = new Thickness (1);
+        view.Margin.CanFocus = true;
+        view.Margin.TabStop = TabBehavior.TabStop;
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // Test: Get focus chain
+        View [] focusChain = view.GetFocusChain (NavigationDirection.Forward, TabBehavior.TabStop);
+
+        // Expected: Margin should be in the focus chain
+        Assert.DoesNotContain (view.Margin, focusChain);
+
+        view.Dispose ();
+    }
+
+    #endregion
+
+    #region Mixed Scenarios
+
+    [Fact]
+    [Trait ("Category", "Adornment")]
+    [Trait ("Category", "Navigation")]
+    public void AdvanceFocus_Nested_Views_With_Adornment_SubViews ()
+    {
+        // Setup: Nested views where parent has adornment subviews
+        View parent = new ()
+        {
+            Id = "parent",
+            Width = 30,
+            Height = 30,
+            CanFocus = true
+        };
+
+        parent.Padding!.Thickness = new Thickness (2);
+
+        View parentPaddingButton = new ()
+        {
+            Id = "parentPaddingButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 8,
+            Height = 1
+        };
+
+        parent.Padding.Add (parentPaddingButton);
+
+        View child = new ()
+        {
+            Id = "child",
+            Width = 10,
+            Height = 10,
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop
+        };
+
+        parent.Add (child);
+
+        child.Padding!.Thickness = new Thickness (1);
+
+        View childPaddingButton = new ()
+        {
+            Id = "childPaddingButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        child.Padding.Add (childPaddingButton);
+
+        parent.BeginInit ();
+        parent.EndInit ();
+
+        // Test: Advance focus should navigate through parent padding, child, and child padding
+        parent.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+
+        // Track which views receive focus
+        List<string> focusedIds = new ();
+
+        // Navigate multiple times to test nested navigation (extra iteration to allow for wrapping)
+        for (var i = 0; i < 5; i++)
+        {
+            if (parentPaddingButton.HasFocus)
+            {
+                focusedIds.Add ("parentPaddingButton");
+            }
+            else if (child.HasFocus)
+            {
+                focusedIds.Add ("child");
+            }
+            else if (childPaddingButton.HasFocus)
+            {
+                focusedIds.Add ("childPaddingButton");
+            }
+
+            parent.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        }
+
+        // Expected: Navigation should reach all elements including adornment subviews
+        // This will likely show incomplete navigation, proving the bug exists
+        Assert.True (
+                     focusedIds.Count > 0,
+                     "At least some navigation should occur (this test documents current behavior)"
+                    );
+
+        parent.Dispose ();
+    }
+
+    #endregion
+
+    #region TabGroup Behavior Tests
+
+
+    #endregion
+
+    #region Edge Cases
+
+    [Fact]
+    [Trait ("Category", "Adornment")]
+    [Trait ("Category", "Navigation")]
+    public void AdvanceFocus_Padding_With_No_Thickness_Should_Not_Participate ()
+    {
+        // Setup: View with Padding that has no thickness but has subviews
+        View view = new ()
+        {
+            Id = "view",
+            Width = 10,
+            Height = 10,
+            CanFocus = true
+        };
+
+        // Padding has default Thickness.Empty
+        View paddingButton = new ()
+        {
+            Id = "paddingButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Padding!.Add (paddingButton);
+
+        View contentButton = new ()
+        {
+            Id = "contentButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Add (contentButton);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // Test: Navigate - should only focus content since Padding has no thickness
+        view.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.True (contentButton.HasFocus, "Content should get focus");
+
+        view.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+
+        // Expected: Should wrap back to content, not go to padding
+        Assert.True (contentButton.HasFocus, "Should stay in content when Padding has no thickness");
+        Assert.False (paddingButton.HasFocus, "Padding button should not receive focus");
+
+        view.Dispose ();
+    }
+
+    [Fact]
+    [Trait ("Category", "Adornment")]
+    [Trait ("Category", "Navigation")]
+    public void AdvanceFocus_Disabled_Adornment_SubView_Should_Be_Skipped ()
+    {
+        // Setup: View with disabled subview in Padding
+        View view = new ()
+        {
+            Id = "view",
+            Width = 10,
+            Height = 10,
+            CanFocus = true
+        };
+
+        view.Padding!.Thickness = new Thickness (1);
+
+        View paddingButton = new ()
+        {
+            Id = "paddingButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            Enabled = false, // Disabled
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Padding.Add (paddingButton);
+
+        View contentButton = new ()
+        {
+            Id = "contentButton",
+            CanFocus = true,
+            TabStop = TabBehavior.TabStop,
+            X = 0,
+            Y = 0,
+            Width = 5,
+            Height = 1
+        };
+
+        view.Add (contentButton);
+
+        view.BeginInit ();
+        view.EndInit ();
+
+        // Test: Navigate - disabled padding button should be skipped
+        view.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+        Assert.True (contentButton.HasFocus, "Content should get focus");
+
+        view.AdvanceFocus (NavigationDirection.Forward, TabBehavior.TabStop);
+
+        // Expected: Should wrap back to content, skipping disabled padding button
+        Assert.True (contentButton.HasFocus, "Should skip disabled padding button");
+        Assert.False (paddingButton.HasFocus, "Disabled padding button should not receive focus");
+
+        view.Dispose ();
+    }
+
+    #endregion
+}

+ 11 - 1
Tests/UnitTestsParallelizable/ViewBase/Navigation/AllViewsNavigationTests.cs

@@ -26,6 +26,11 @@ public class AllViewsNavigationTests (ITestOutputHelper output) : TestsAllViews
             return;
         }
 
+        if (view is IDesignable designable)
+        {
+            designable.EnableForDesign ();
+        }
+
         IApplication app = Application.Create ();
         app.Begin (new Runnable<bool> () { CanFocus = true });
 
@@ -45,7 +50,7 @@ public class AllViewsNavigationTests (ITestOutputHelper output) : TestsAllViews
 
         if (view.TabStop == TabBehavior.TabGroup)
         {
-            navKeys = new [] { Key.F6, Key.F6.WithShift };
+            navKeys = [Key.F6, Key.F6.WithShift];
         }
 
         var left = false;
@@ -113,6 +118,11 @@ public class AllViewsNavigationTests (ITestOutputHelper output) : TestsAllViews
             return;
         }
 
+        if (view is IDesignable designable)
+        {
+            designable.EnableForDesign ();
+        }
+
         IApplication app = Application.Create ();
         app.Begin (new Runnable<bool> () { CanFocus = true });
 

+ 420 - 103
Tests/UnitTestsParallelizable/ViewBase/SubviewTests.cs

@@ -6,16 +6,14 @@ public class SubViewTests
     [Fact]
     public void SuperViewChanged_Raised_On_Add ()
     {
-        var super = new View { };
+        var super = new View ();
         var sub = new View ();
 
-        int superRaisedCount = 0;
-        int subRaisedCount = 0;
+        var superRaisedCount = 0;
+        var subRaisedCount = 0;
+
+        super.SuperViewChanged += (s, e) => { superRaisedCount++; };
 
-        super.SuperViewChanged += (s, e) =>
-                              {
-                                  superRaisedCount++;
-                              };
         sub.SuperViewChanged += (s, e) =>
                                 {
                                     if (sub.SuperView is { })
@@ -34,23 +32,21 @@ public class SubViewTests
     [Fact]
     public void SuperViewChanged_Raised_On_Remove ()
     {
-        var super = new View { };
+        var super = new View ();
         var sub = new View ();
 
-        int superRaisedCount = 0;
-        int subRaisedCount = 0;
+        var superRaisedCount = 0;
+        var subRaisedCount = 0;
+
+        super.SuperViewChanged += (s, e) => { superRaisedCount++; };
 
-        super.SuperViewChanged += (s, e) =>
+        sub.SuperViewChanged += (s, e) =>
                                 {
-                                    superRaisedCount++;
+                                    if (sub.SuperView is null)
+                                    {
+                                        subRaisedCount++;
+                                    }
                                 };
-        sub.SuperViewChanged += (s, e) =>
-                              {
-                                  if (sub.SuperView is null)
-                                  {
-                                      subRaisedCount++;
-                                  }
-                              };
 
         super.Add (sub);
         Assert.True (super.SubViews.Count == 1);
@@ -95,6 +91,13 @@ public class SubViewTests
         Assert.Equal (new (1, 1), view.GetContentSize ());
     }
 
+    [Fact]
+    public void Add_Margin_Throws ()
+    {
+        View view = new ();
+        Assert.Throws<InvalidOperationException> (() => view.Margin!.Add (new View ()));
+    }
+
     [Fact]
     public void Remove_Does_Not_Impact_ContentSize ()
     {
@@ -392,18 +395,12 @@ public class SubViewTests
         var view = new View ();
         var superView = new View ();
 
-        int superViewChangedCount = 0;
-        int superViewChangingCount = 0;
+        var superViewChangedCount = 0;
+        var superViewChangingCount = 0;
 
-        view.SuperViewChanged += (s, e) =>
-        {
-            superViewChangedCount++;
-        };
+        view.SuperViewChanged += (s, e) => { superViewChangedCount++; };
 
-        view.SuperViewChanging += (s, e) =>
-        {
-            superViewChangingCount++;
-        };
+        view.SuperViewChanging += (s, e) => { superViewChangingCount++; };
 
         // Act
         superView.Add (view);
@@ -411,7 +408,6 @@ public class SubViewTests
         // Assert
         Assert.Equal (1, superViewChangingCount);
         Assert.Equal (1, superViewChangedCount);
-
     }
 
     [Fact]
@@ -450,7 +446,6 @@ public class SubViewTests
         top2.Dispose ();
     }
 
-
     [Fact]
     public void Initialized_Event_Comparing_With_Added_Event ()
     {
@@ -479,10 +474,10 @@ public class SubViewTests
         int tc = 0, wc = 0, v1c = 0, v2c = 0, sv1c = 0;
 
         winAddedToTop.SubViewAdded += (s, e) =>
-        {
-            Assert.Equal (e.SuperView!.Frame.Width, winAddedToTop.Frame.Width);
-            Assert.Equal (e.SuperView.Frame.Height, winAddedToTop.Frame.Height);
-        };
+                                      {
+                                          Assert.Equal (e.SuperView!.Frame.Width, winAddedToTop.Frame.Width);
+                                          Assert.Equal (e.SuperView.Frame.Height, winAddedToTop.Frame.Height);
+                                      };
 
         v1AddedToWin.SubViewAdded += (s, e) =>
                                      {
@@ -503,69 +498,70 @@ public class SubViewTests
                                     };
 
         top.Initialized += (s, e) =>
-        {
-            tc++;
-            Assert.Equal (1, tc);
-            Assert.Equal (1, wc);
-            Assert.Equal (1, v1c);
-            Assert.Equal (1, v2c);
-            Assert.Equal (1, sv1c);
-
-            Assert.True (top.CanFocus);
-            Assert.True (winAddedToTop.CanFocus);
-            Assert.False (v1AddedToWin.CanFocus);
-            Assert.False (v2AddedToWin.CanFocus);
-            Assert.False (svAddedTov1.CanFocus);
-
-            top.Layout ();
-        };
+                           {
+                               tc++;
+                               Assert.Equal (1, tc);
+                               Assert.Equal (1, wc);
+                               Assert.Equal (1, v1c);
+                               Assert.Equal (1, v2c);
+                               Assert.Equal (1, sv1c);
+
+                               Assert.True (top.CanFocus);
+                               Assert.True (winAddedToTop.CanFocus);
+                               Assert.False (v1AddedToWin.CanFocus);
+                               Assert.False (v2AddedToWin.CanFocus);
+                               Assert.False (svAddedTov1.CanFocus);
+
+                               top.Layout ();
+                           };
 
         winAddedToTop.Initialized += (s, e) =>
-        {
-            wc++;
-            Assert.Equal (top.Viewport.Width, winAddedToTop.Frame.Width);
-            Assert.Equal (top.Viewport.Height, winAddedToTop.Frame.Height);
-        };
+                                     {
+                                         wc++;
+                                         Assert.Equal (top.Viewport.Width, winAddedToTop.Frame.Width);
+                                         Assert.Equal (top.Viewport.Height, winAddedToTop.Frame.Height);
+                                     };
 
         v1AddedToWin.Initialized += (s, e) =>
-        {
-            v1c++;
-
-            // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
-            // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
-            // in no way should the v1AddedToWin.Frame be the same as the Top.Frame/Viewport
-            // as it is a subview of winAddedToTop, which has a border!
-            //Assert.Equal (top.Viewport.Width,  v1AddedToWin.Frame.Width);
-            //Assert.Equal (top.Viewport.Height, v1AddedToWin.Frame.Height);
-        };
+                                    {
+                                        v1c++;
+
+                                        // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
+                                        // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
+                                        // in no way should the v1AddedToWin.Frame be the same as the Top.Frame/Viewport
+                                        // as it is a subview of winAddedToTop, which has a border!
+                                        //Assert.Equal (top.Viewport.Width,  v1AddedToWin.Frame.Width);
+                                        //Assert.Equal (top.Viewport.Height, v1AddedToWin.Frame.Height);
+                                    };
 
         v2AddedToWin.Initialized += (s, e) =>
-        {
-            v2c++;
-
-            // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
-            // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
-            // in no way should the v2AddedToWin.Frame be the same as the Top.Frame/Viewport
-            // as it is a subview of winAddedToTop, which has a border!
-            //Assert.Equal (top.Viewport.Width,  v2AddedToWin.Frame.Width);
-            //Assert.Equal (top.Viewport.Height, v2AddedToWin.Frame.Height);
-        };
+                                    {
+                                        v2c++;
+
+                                        // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
+                                        // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
+                                        // in no way should the v2AddedToWin.Frame be the same as the Top.Frame/Viewport
+                                        // as it is a subview of winAddedToTop, which has a border!
+                                        //Assert.Equal (top.Viewport.Width,  v2AddedToWin.Frame.Width);
+                                        //Assert.Equal (top.Viewport.Height, v2AddedToWin.Frame.Height);
+                                    };
 
         svAddedTov1.Initialized += (s, e) =>
-        {
-            sv1c++;
-
-            // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
-            // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
-            // in no way should the svAddedTov1.Frame be the same as the Top.Frame/Viewport
-            // because sv1AddedTov1 is a subview of v1AddedToWin, which is a subview of
-            // winAddedToTop, which has a border!
-            //Assert.Equal (top.Viewport.Width,  svAddedTov1.Frame.Width);
-            //Assert.Equal (top.Viewport.Height, svAddedTov1.Frame.Height);
-            Assert.False (svAddedTov1.CanFocus);
-            //Assert.Throws<InvalidOperationException> (() => svAddedTov1.CanFocus = true);
-            Assert.False (svAddedTov1.CanFocus);
-        };
+                                   {
+                                       sv1c++;
+
+                                       // Top.Frame: 0, 0, 80, 25; Top.Viewport: 0, 0, 80, 25
+                                       // BUGBUG: This is wrong, it should be 78, 23. This test has always been broken.
+                                       // in no way should the svAddedTov1.Frame be the same as the Top.Frame/Viewport
+                                       // because sv1AddedTov1 is a subview of v1AddedToWin, which is a subview of
+                                       // winAddedToTop, which has a border!
+                                       //Assert.Equal (top.Viewport.Width,  svAddedTov1.Frame.Width);
+                                       //Assert.Equal (top.Viewport.Height, svAddedTov1.Frame.Height);
+                                       Assert.False (svAddedTov1.CanFocus);
+
+                                       //Assert.Throws<InvalidOperationException> (() => svAddedTov1.CanFocus = true);
+                                       Assert.False (svAddedTov1.CanFocus);
+                                   };
 
         v1AddedToWin.Add (svAddedTov1);
         winAddedToTop.Add (v1AddedToWin, v2AddedToWin);
@@ -639,7 +635,7 @@ public class SubViewTests
         superView.Add (subView1, subView2, subView3);
 
         // Act
-        var removedViews = superView.RemoveAll ();
+        IReadOnlyCollection<View> removedViews = superView.RemoveAll ();
 
         // Assert
         Assert.Empty (superView.SubViews);
@@ -662,7 +658,7 @@ public class SubViewTests
         superView.Add (subView1, subView2, subView3, subView4);
 
         // Act
-        var removedViews = superView.RemoveAll<Button> ();
+        IReadOnlyCollection<Button> removedViews = superView.RemoveAll<Button> ();
 
         // Assert
         Assert.Equal (3, superView.SubViews.Count);
@@ -683,7 +679,7 @@ public class SubViewTests
         superView.Add (subView1, subView2, subView3);
 
         // Act
-        var removedViews = superView.RemoveAll<Button> ();
+        IReadOnlyCollection<Button> removedViews = superView.RemoveAll<Button> ();
 
         // Assert
         Assert.Equal (2, superView.SubViews.Count);
@@ -700,7 +696,7 @@ public class SubViewTests
         var superView = new View ();
         var subView = new View ();
 
-        var events = new List<string> ();
+        List<string> events = new ();
 
         subView.SuperViewChanging += (s, e) => { events.Add ("SuperViewChanging"); };
 
@@ -722,7 +718,7 @@ public class SubViewTests
         var superView = new View ();
         var subView = new View ();
 
-        View? currentValueInEvent = new View (); // Set to non-null to ensure it gets updated
+        var currentValueInEvent = new View (); // Set to non-null to ensure it gets updated
         View? newValueInEvent = null;
 
         subView.SuperViewChanging += (s, e) =>
@@ -749,7 +745,7 @@ public class SubViewTests
         superView.Add (subView);
 
         View? currentValueInEvent = null;
-        View? newValueInEvent = new View (); // Set to non-null to ensure it gets updated
+        var newValueInEvent = new View (); // Set to non-null to ensure it gets updated
 
         subView.SuperViewChanging += (s, e) =>
                                      {
@@ -770,7 +766,7 @@ public class SubViewTests
     {
         // Arrange
         using IApplication app = Application.Create ();
-        var runnable = new Runnable<bool> ();
+        Runnable<bool> runnable = new ();
         var subView = new View ();
 
         runnable.Add (subView);
@@ -781,11 +777,11 @@ public class SubViewTests
         subView.SuperViewChanging += (s, e) =>
                                      {
                                          Assert.NotNull (s);
+
                                          // At this point, SuperView is still set, so App should be accessible
                                          appInEvent = (s as View)?.App;
                                      };
 
-
         Assert.NotNull (runnable.App);
 
         // Act
@@ -804,7 +800,7 @@ public class SubViewTests
     {
         // Arrange
         var superView = new View ();
-        var events = new List<string> ();
+        List<string> events = new ();
 
         var subView = new TestViewWithSuperViewEvents (events);
 
@@ -854,6 +850,7 @@ public class SubViewTests
         protected override bool OnSuperViewChanging (ValueChangingEventArgs<View?> args)
         {
             _events.Add ("OnSuperViewChanging");
+
             return base.OnSuperViewChanging (args);
         }
 
@@ -907,10 +904,7 @@ public class SubViewTests
         var subView = new TestViewThatCancelsChange ();
 
         var eventRaised = false;
-        subView.SuperViewChanging += (s, e) =>
-                                     {
-                                         eventRaised = true;
-                                     };
+        subView.SuperViewChanging += (s, e) => { eventRaised = true; };
 
         // Act
         superView.Add (subView);
@@ -983,4 +977,327 @@ public class SubViewTests
             return true; // Always cancel the change
         }
     }
+
+    #region GetSubViews Tests
+
+    [Fact]
+    public void GetSubViews_Returns_Empty_Collection_When_No_SubViews ()
+    {
+        // Arrange
+        View view = new ();
+
+        // Act
+        IReadOnlyCollection<View> result = view.GetSubViews ();
+
+        // Assert
+        Assert.NotNull (result);
+        Assert.Empty (result);
+    }
+
+    [Fact]
+    public void GetSubViews_Returns_Direct_SubViews_By_Default ()
+    {
+        // Arrange
+        View superView = new ();
+        View subView1 = new () { Id = "subView1" };
+        View subView2 = new () { Id = "subView2" };
+        View subView3 = new () { Id = "subView3" };
+
+        superView.Add (subView1, subView2, subView3);
+
+        // Act
+        IReadOnlyCollection<View> result = superView.GetSubViews ();
+
+        // Assert
+        Assert.NotNull (result);
+        Assert.Equal (3, result.Count);
+        Assert.Contains (subView1, result);
+        Assert.Contains (subView2, result);
+        Assert.Contains (subView3, result);
+    }
+
+    [Fact]
+    public void GetSubViews_Does_Not_Include_Adornment_SubViews_By_Default ()
+    {
+        // Arrange
+        View superView = new ();
+        View subView = new () { Id = "subView" };
+
+        superView.Add (subView);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        // Add a subview to the Border (e.g., ShadowView)
+        View borderSubView = new () { Id = "borderSubView" };
+        superView.Border!.Add (borderSubView);
+
+        // Act
+        IReadOnlyCollection<View> result = superView.GetSubViews ();
+
+        // Assert
+        Assert.Single (result);
+        Assert.Contains (subView, result);
+        Assert.DoesNotContain (borderSubView, result);
+    }
+
+    [Fact]
+    public void GetSubViews_Includes_Border_SubViews_When_IncludeAdornments_Is_True ()
+    {
+        // Arrange
+        View superView = new ();
+        View subView = new () { Id = "subView" };
+
+        superView.Add (subView);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        // Add a subview to the Border
+        View borderSubView = new () { Id = "borderSubView" };
+        // Thickness matters
+        superView.Border!.Thickness = new (1);
+        superView.Border!.Add (borderSubView);
+
+        // Act
+        IReadOnlyCollection<View> result = superView.GetSubViews (includeBorder: true);
+
+        // Assert
+        Assert.Equal (2, result.Count);
+        Assert.Contains (subView, result);
+        Assert.Contains (borderSubView, result);
+    }
+
+    [Fact]
+    public void GetSubViews_Includes_Padding_SubViews_When_IncludeAdornments_Is_True ()
+    {
+        // Arrange
+        View superView = new ();
+        View subView = new () { Id = "subView" };
+
+        superView.Add (subView);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        // Add a subview to the Padding
+        View paddingSubView = new () { Id = "paddingSubView" };
+        // Thickness matters
+        superView.Padding!.Thickness = new (1);
+        superView.Padding!.Add (paddingSubView);
+
+        // Act
+        IReadOnlyCollection<View> result = superView.GetSubViews (includePadding: true);
+
+        // Assert
+        Assert.Equal (2, result.Count);
+        Assert.Contains (subView, result);
+        Assert.Contains (paddingSubView, result);
+    }
+
+    [Fact]
+    public void GetSubViews_Includes_All_Adornment_SubViews_When_IncludeAdornments_Is_True ()
+    {
+        // Arrange
+        View superView = new ();
+        View subView1 = new () { Id = "subView1" };
+        View subView2 = new () { Id = "subView2" };
+
+        superView.Add (subView1, subView2);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        // Add subviews to each adornment
+        View borderSubView = new () { Id = "borderSubView" };
+        View paddingSubView = new () { Id = "paddingSubView" };
+
+        // Thickness matters
+        //superView.Margin!.Thickness = new  (1);
+        //superView.Margin!.Add (marginSubView);
+        superView.Border!.Thickness = new  (1);
+        superView.Border!.Add (borderSubView);
+        superView.Padding!.Thickness = new  (1);
+        superView.Padding!.Add (paddingSubView);
+
+        // Act
+        IReadOnlyCollection<View> result = superView.GetSubViews (true, true, true);
+
+        // Assert
+        Assert.Equal (4, result.Count);
+        Assert.Contains (subView1, result);
+        Assert.Contains (subView2, result);
+        Assert.Contains (borderSubView, result);
+        Assert.Contains (paddingSubView, result);
+    }
+
+    [Fact]
+    public void GetSubViews_Returns_Correct_Order ()
+    {
+        // Arrange
+        View superView = new ();
+        View subView1 = new () { Id = "subView1" };
+        View subView2 = new () { Id = "subView2" };
+
+        superView.Add (subView1, subView2);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        View borderSubView = new () { Id = "borderSubView" };
+        View paddingSubView = new () { Id = "paddingSubView" };
+
+        // Thickness matters
+        superView.Border!.Thickness = new (1);
+        superView.Border!.Add (borderSubView);
+        superView.Padding!.Thickness = new (1);
+        superView.Padding!.Add (paddingSubView);
+
+        // Act
+        IReadOnlyCollection<View> result = superView.GetSubViews (true, true, true);
+        List<View> resultList = result.ToList ();
+
+        // Assert - Order should be: direct SubViews, Border, Padding
+        Assert.Equal (4, resultList.Count);
+        Assert.Equal (subView1, resultList [0]);
+        Assert.Equal (subView2, resultList [1]);
+        Assert.Equal (borderSubView, resultList [2]);
+        Assert.Equal (paddingSubView, resultList [3]);
+    }
+
+    [Fact]
+    public void GetSubViews_Returns_Snapshot_Safe_For_Modification ()
+    {
+        // Arrange
+        View superView = new ();
+        View subView1 = new () { Id = "subView1" };
+        View subView2 = new () { Id = "subView2" };
+
+        superView.Add (subView1, subView2);
+
+        // Act
+        IReadOnlyCollection<View> result = superView.GetSubViews ();
+
+        // Modify the SuperView's SubViews
+        View subView3 = new () { Id = "subView3" };
+        superView.Add (subView3);
+
+        // Assert - The snapshot should not include subView3
+        Assert.Equal (2, result.Count);
+        Assert.Contains (subView1, result);
+        Assert.Contains (subView2, result);
+        Assert.DoesNotContain (subView3, result);
+    }
+
+    [Fact]
+    public void GetSubViews_Multiple_SubViews_In_Each_Adornment ()
+    {
+        // Arrange
+        View superView = new ();
+        View subView = new () { Id = "subView" };
+
+        superView.Add (subView);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        // Add multiple subviews to each adornment
+        View borderSubView1 = new () { Id = "borderSubView1" };
+        View borderSubView2 = new () { Id = "borderSubView2" };
+        View paddingSubView1 = new () { Id = "paddingSubView1" };
+        View paddingSubView2 = new () { Id = "paddingSubView2" };
+
+        // Thickness matters
+        superView.Border!.Thickness = new (1);
+        superView.Border!.Add (borderSubView1, borderSubView2);
+        // Thickness matters
+        superView.Padding!.Thickness = new (1);
+        superView.Padding!.Add (paddingSubView1, paddingSubView2);
+
+        // Act
+        IReadOnlyCollection<View> result = superView.GetSubViews (true, true, true);
+
+        // Assert
+        Assert.Equal (5, result.Count);
+        Assert.Contains (subView, result);
+        Assert.Contains (borderSubView1, result);
+        Assert.Contains (borderSubView2, result);
+        Assert.Contains (paddingSubView1, result);
+        Assert.Contains (paddingSubView2, result);
+    }
+
+    [Fact]
+    public void GetSubViews_Works_With_Adornment_Itself ()
+    {
+        // Arrange - Test that an Adornment (which is a View) can also have GetSubViews called
+        View view = new ();
+        view.BeginInit ();
+        view.EndInit ();
+
+        View paddingSubView = new () { Id = "paddingSubView" };
+        view.Padding!.Add (paddingSubView);
+
+        // Act - Call GetSubViews on the Margin itself
+        IReadOnlyCollection<View> result = view.Padding.GetSubViews ();
+
+        // Assert
+        Assert.Single (result);
+        Assert.Contains (paddingSubView, result);
+    }
+
+    [Fact]
+    public void GetSubViews_Handles_Null_Adornments_Gracefully ()
+    {
+        // Arrange - Create an Adornment view which doesn't have its own adornments
+        View view = new ();
+        view.BeginInit ();
+        view.EndInit ();
+
+        // Border is an Adornment and doesn't have Margin, Border, Padding
+        View borderSubView = new () { Id = "borderSubView" };
+        view.Border!.Add (borderSubView);
+
+        // Act - GetSubViews on Border (an Adornment) with includeAdornments
+        IReadOnlyCollection<View> result = view.Border.GetSubViews (true);
+
+        // Assert - Should only return direct subviews, not crash
+        Assert.Single (result);
+        Assert.Contains (borderSubView, result);
+    }
+
+    [Fact]
+    public void GetSubViews_Returns_IReadOnlyCollection ()
+    {
+        // Arrange
+        View superView = new ();
+        View subView = new () { Id = "subView" };
+        superView.Add (subView);
+
+        // Act
+        IReadOnlyCollection<View> result = superView.GetSubViews ();
+
+        // Assert
+        Assert.IsAssignableFrom<IReadOnlyCollection<View>> (result);
+
+        // Verify Count property is available and single item
+        Assert.Single (result);
+    }
+
+    [Fact]
+    public void GetSubViews_Empty_Adornments_Do_Not_Add_Nulls ()
+    {
+        // Arrange
+        View superView = new ();
+        View subView = new () { Id = "subView" };
+
+        superView.Add (subView);
+        superView.BeginInit ();
+        superView.EndInit ();
+
+        // Don't add any subviews to adornments
+
+        // Act
+        IReadOnlyCollection<View> result = superView.GetSubViews (true);
+
+        // Assert - Should only have the direct subview, no nulls
+        Assert.Single (result);
+        Assert.Contains (subView, result);
+        Assert.All (result, Assert.NotNull);
+    }
 }
+
+#endregion GetSubViews Tests

+ 1 - 1
Tests/UnitTestsParallelizable/Views/TextViewTests.cs

@@ -1833,7 +1833,7 @@ public class TextViewTests
     [Fact]
     public void Space_Key_Types_Space ()
     {
-        var view = new TextView ();
+        TextView view = new ();
 
         view.NewKeyDownEvent (Key.Space);
 

+ 479 - 0
Tests/UnitTestsParallelizable/Views/WizardStepTests.cs

@@ -0,0 +1,479 @@
+namespace ViewsTests;
+
+[Collection ("Global Test Setup")]
+public class WizardStepTests
+{
+    #region Constructor Tests
+
+    [Fact]
+    public void Constructor_Initializes_Properties ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.NotNull (step);
+        Assert.True (step.CanFocus);
+        Assert.Equal (TabBehavior.TabStop, step.TabStop);
+        Assert.Equal (LineStyle.None, step.BorderStyle);
+        Assert.IsType<DimFill> (step.Width);
+        Assert.IsType<DimFill> (step.Height);
+    }
+
+    [Fact]
+    public void Constructor_Sets_Default_Button_Text ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.Equal (string.Empty, step.BackButtonText);
+        Assert.Equal (string.Empty, step.NextButtonText);
+    }
+
+    #endregion Constructor Tests
+
+    #region Title Tests
+
+    [Fact]
+    public void Title_Can_Be_Set ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        string title = "Test Step";
+
+        // Act
+        step.Title = title;
+
+        // Assert
+        Assert.Equal (title, step.Title);
+    }
+
+    [Fact]
+    public void Title_Change_Raises_TitleChanged_Event ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        var eventRaised = false;
+        string? newTitle = null;
+
+        step.TitleChanged += (sender, args) =>
+                             {
+                                 eventRaised = true;
+                                 newTitle = args.Value;
+                             };
+
+        // Act
+        step.Title = "New Title";
+
+        // Assert
+        Assert.True (eventRaised);
+        Assert.Equal ("New Title", newTitle);
+    }
+
+    #endregion Title Tests
+
+    #region HelpText Tests
+
+    [Fact]
+    public void HelpText_Can_Be_Set ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        string helpText = "This is help text";
+
+        // Act
+        step.HelpText = helpText;
+
+        // Assert
+        Assert.Equal (helpText, step.HelpText);
+    }
+
+    [Fact]
+    public void HelpText_Empty_By_Default ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.Equal (string.Empty, step.HelpText);
+    }
+
+    [Fact]
+    public void HelpText_Setting_Calls_ShowHide ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        step.BeginInit ();
+        step.EndInit ();
+
+        // Act - Setting help text should adjust padding
+        step.HelpText = "Help text content";
+
+        // Assert - Padding should have right thickness when help text is present
+        Assert.True (step.Padding!.Thickness.Right > 0);
+    }
+
+    [Fact]
+    public void HelpText_Clearing_Removes_Padding ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        step.BeginInit ();
+        step.EndInit ();
+        step.HelpText = "Help text content";
+
+        // Act - Clear help text
+        step.HelpText = string.Empty;
+
+        // Assert - Padding right should be 0 when help text is empty
+        Assert.Equal (0, step.Padding!.Thickness.Right);
+    }
+
+    #endregion HelpText Tests
+
+    #region BackButtonText Tests
+
+    [Fact]
+    public void BackButtonText_Can_Be_Set ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        string buttonText = "Previous";
+
+        // Act
+        step.BackButtonText = buttonText;
+
+        // Assert
+        Assert.Equal (buttonText, step.BackButtonText);
+    }
+
+    [Fact]
+    public void BackButtonText_Empty_By_Default ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.Equal (string.Empty, step.BackButtonText);
+    }
+
+    #endregion BackButtonText Tests
+
+    #region NextButtonText Tests
+
+    [Fact]
+    public void NextButtonText_Can_Be_Set ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        string buttonText = "Continue";
+
+        // Act
+        step.NextButtonText = buttonText;
+
+        // Assert
+        Assert.Equal (buttonText, step.NextButtonText);
+    }
+
+    [Fact]
+    public void NextButtonText_Empty_By_Default ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.Equal (string.Empty, step.NextButtonText);
+    }
+
+    #endregion NextButtonText Tests
+
+    #region SubView Tests
+
+    [Fact]
+    public void Can_Add_SubViews ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        Label label = new () { Text = "Test Label" };
+
+        // Act
+        step.Add (label);
+
+        // Assert
+        Assert.Contains (label, step.SubViews);
+    }
+
+    [Fact]
+    public void Can_Add_Multiple_SubViews ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        Label label1 = new () { Text = "Label 1" };
+        Label label2 = new () { Text = "Label 2" };
+        TextField textField = new () { Width = 10 };
+
+        // Act
+        step.Add (label1, label2, textField);
+
+        // Assert
+        Assert.Equal (3, step.SubViews.Count);
+        Assert.Contains (label1, step.SubViews);
+        Assert.Contains (label2, step.SubViews);
+        Assert.Contains (textField, step.SubViews);
+    }
+
+    #endregion SubView Tests
+
+    #region Enabled Tests
+
+    [Fact]
+    public void Enabled_True_By_Default ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.True (step.Enabled);
+    }
+
+    [Fact]
+    public void Enabled_Can_Be_Set_To_False ()
+    {
+        // Arrange
+        WizardStep step = new ();
+
+        // Act
+        step.Enabled = false;
+
+        // Assert
+        Assert.False (step.Enabled);
+    }
+
+    [Fact]
+    public void Enabled_Change_Raises_EnabledChanged_Event ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        var eventRaised = false;
+
+        step.EnabledChanged += (sender, args) => { eventRaised = true; };
+
+        // Act
+        step.Enabled = false;
+
+        // Assert
+        Assert.True (eventRaised);
+    }
+
+    #endregion Enabled Tests
+
+    #region Visible Tests
+
+    [Fact]
+    public void Visible_True_By_Default ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.True (step.Visible);
+    }
+
+    [Fact]
+    public void Visible_Can_Be_Changed ()
+    {
+        // Arrange
+        WizardStep step = new ();
+
+        // Act
+        step.Visible = false;
+
+        // Assert
+        Assert.False (step.Visible);
+    }
+
+    #endregion Visible Tests
+
+    #region HelpTextView Tests
+
+    [Fact]
+    public void HelpTextView_Added_To_Padding ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        step.BeginInit ();
+        step.EndInit ();
+
+        // Act
+        step.HelpText = "Help content";
+
+        // Assert
+        // The help text view should be in the Padding
+        Assert.True (step.Padding!.SubViews.Count > 0);
+    }
+
+    [Fact]
+    public void HelpTextView_Visible_When_HelpText_Set ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        step.BeginInit ();
+        step.EndInit ();
+
+        // Act
+        step.HelpText = "Help content";
+
+        // Assert
+        // When help text is set, padding right should be non-zero
+        Assert.True (step.Padding!.Thickness.Right > 0);
+    }
+
+    [Fact]
+    public void HelpTextView_Hidden_When_HelpText_Empty ()
+    {
+        // Arrange
+        WizardStep step = new ();
+        step.BeginInit ();
+        step.EndInit ();
+        step.HelpText = "Help content";
+
+        // Act
+        step.HelpText = string.Empty;
+
+        // Assert
+        // When help text is cleared, padding right should be 0
+        Assert.Equal (0, step.Padding!.Thickness.Right);
+    }
+
+    #endregion HelpTextView Tests
+
+    #region Layout Tests
+
+    [Fact]
+    public void Width_Is_Fill_After_Construction ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.IsType<DimFill> (step.Width);
+    }
+
+    [Fact]
+    public void Height_Is_Fill_After_Construction ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.IsType<DimFill> (step.Height);
+    }
+
+    #endregion Layout Tests
+
+    #region Focus Tests
+
+    [Fact]
+    public void CanFocus_True_By_Default ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.True (step.CanFocus);
+    }
+
+    [Fact]
+    public void TabStop_Is_TabStop_By_Default ()
+    {
+        // Arrange & Act
+        WizardStep step = new ();
+
+        // Assert
+        Assert.Equal (TabBehavior.TabStop, step.TabStop);
+    }
+
+    #endregion Focus Tests
+
+    #region BorderStyle Tests
+
+    [Fact]
+    public void BorderStyle_Can_Be_Changed ()
+    {
+        // Arrange
+        WizardStep step = new ();
+
+        // Act
+        step.BorderStyle = LineStyle.Single;
+
+        // Assert
+        Assert.Equal (LineStyle.Single, step.BorderStyle);
+    }
+
+    #endregion BorderStyle Tests
+
+    #region Integration Tests
+
+    [Fact]
+    public void Step_With_HelpText_And_SubViews ()
+    {
+        // Arrange
+        WizardStep step = new ()
+        {
+            Title = "User Information",
+            HelpText = "Please enter your details"
+        };
+
+        Label nameLabel = new () { Text = "Name:" };
+        TextField nameField = new () { X = Pos.Right (nameLabel) + 1, Width = 20 };
+
+        step.Add (nameLabel, nameField);
+        step.BeginInit ();
+        step.EndInit ();
+
+        // Assert
+        Assert.Equal ("User Information", step.Title);
+        Assert.Equal ("Please enter your details", step.HelpText);
+        // SubViews includes the views we added
+        Assert.Contains (nameLabel, step.SubViews);
+        Assert.Contains (nameField, step.SubViews);
+        Assert.True (step.Padding!.Thickness.Right > 0);
+    }
+
+    [Fact]
+    public void Step_With_Custom_Button_Text ()
+    {
+        // Arrange & Act
+        WizardStep step = new ()
+        {
+            Title = "Confirmation",
+            BackButtonText = "Go Back",
+            NextButtonText = "Accept"
+        };
+
+        // Assert
+        Assert.Equal ("Confirmation", step.Title);
+        Assert.Equal ("Go Back", step.BackButtonText);
+        Assert.Equal ("Accept", step.NextButtonText);
+    }
+
+    [Fact]
+    public void Disabled_Step_Maintains_Properties ()
+    {
+        // Arrange
+        WizardStep step = new ()
+        {
+            Title = "Optional Step",
+            HelpText = "This step is optional",
+            Enabled = false
+        };
+
+        // Assert
+        Assert.Equal ("Optional Step", step.Title);
+        Assert.Equal ("This step is optional", step.HelpText);
+        Assert.False (step.Enabled);
+    }
+
+    #endregion Integration Tests
+}

+ 1019 - 0
Tests/UnitTestsParallelizable/Views/WizardTests.cs

@@ -0,0 +1,1019 @@
+namespace ViewsTests;
+
+[Collection ("Global Test Setup")]
+public class WizardTests
+{
+    #region Constructor Tests
+
+    [Fact]
+    public void Constructor_Initializes_Properties ()
+    {
+        // Arrange & Act
+        Wizard wizard = new ();
+
+        // Assert
+        Assert.NotNull (wizard);
+        Assert.NotNull (wizard.BackButton);
+        Assert.NotNull (wizard.NextFinishButton);
+        Assert.Null (wizard.CurrentStep);
+        Assert.Equal (LineStyle.Dotted, wizard.BorderStyle);
+        Assert.False (wizard.Arrangement.HasFlag (ViewArrangement.Movable));
+        Assert.False (wizard.Arrangement.HasFlag (ViewArrangement.Resizable));
+    }
+
+    [Fact]
+    public void Constructor_Sets_Button_Properties ()
+    {
+        // Arrange & Act
+        Wizard wizard = new ();
+
+        // Assert
+        Assert.Equal (Strings.wzBack, wizard.BackButton.Text);
+        Assert.Equal (Strings.wzFinish, wizard.NextFinishButton.Text);
+        Assert.True (wizard.NextFinishButton.IsDefault);
+        Assert.Equal (0, wizard.BackButton.X);
+        Assert.Equal (Pos.AnchorEnd (), wizard.NextFinishButton.X);
+    }
+
+    #endregion Constructor Tests
+
+    #region AddStep Tests
+
+    [Fact]
+    public void AddStep_Adds_Step_To_Wizard ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step = new () { Title = "Step 1" };
+
+        // Act
+        wizard.AddStep (step);
+
+        // Assert
+        Assert.Single (wizard.SubViews);
+        Assert.Contains (step, wizard.SubViews);
+    }
+
+    [Fact]
+    public void AddStep_Multiple_Steps_Maintains_Order ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        WizardStep step3 = new () { Title = "Step 3" };
+
+        // Act
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+
+        // Assert
+        Assert.Equal (3, wizard.SubViews.Count);
+        Assert.Equal (step1, wizard.GetFirstStep ());
+        Assert.Equal (step3, wizard.GetLastStep ());
+    }
+
+    [Fact]
+    public void AddStep_Sets_Width_And_Height_To_Fill ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step = new () { Title = "Step 1" };
+
+        // Act
+        wizard.AddStep (step);
+
+        // Assert
+        Assert.IsType<DimFill> (step.Width);
+        Assert.IsType<DimFill> (step.Height);
+    }
+
+    #endregion AddStep Tests
+
+    #region GetFirstStep Tests
+
+    [Fact]
+    public void GetFirstStep_Returns_Null_When_No_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+
+        // Act
+        WizardStep? result = wizard.GetFirstStep ();
+
+        // Assert
+        Assert.Null (result);
+    }
+
+    [Fact]
+    public void GetFirstStep_Returns_First_Enabled_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+
+        // Act
+        WizardStep? result = wizard.GetFirstStep ();
+
+        // Assert
+        Assert.Equal (step1, result);
+    }
+
+    [Fact]
+    public void GetFirstStep_Skips_Disabled_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1", Enabled = false };
+        WizardStep step2 = new () { Title = "Step 2" };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+
+        // Act
+        WizardStep? result = wizard.GetFirstStep ();
+
+        // Assert
+        Assert.Equal (step2, result);
+    }
+
+    [Fact]
+    public void GetFirstStep_Returns_Null_When_All_Steps_Disabled ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1", Enabled = false };
+        WizardStep step2 = new () { Title = "Step 2", Enabled = false };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+
+        // Act
+        WizardStep? result = wizard.GetFirstStep ();
+
+        // Assert
+        Assert.Null (result);
+    }
+
+    #endregion GetFirstStep Tests
+
+    #region GetLastStep Tests
+
+    [Fact]
+    public void GetLastStep_Returns_Null_When_No_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+
+        // Act
+        WizardStep? result = wizard.GetLastStep ();
+
+        // Assert
+        Assert.Null (result);
+    }
+
+    [Fact]
+    public void GetLastStep_Returns_Last_Enabled_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+
+        // Act
+        WizardStep? result = wizard.GetLastStep ();
+
+        // Assert
+        Assert.Equal (step3, result);
+    }
+
+    [Fact]
+    public void GetLastStep_Skips_Disabled_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        WizardStep step3 = new () { Title = "Step 3", Enabled = false };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+
+        // Act
+        WizardStep? result = wizard.GetLastStep ();
+
+        // Assert
+        Assert.Equal (step2, result);
+    }
+
+    [Fact]
+    public void GetLastStep_Returns_Null_When_All_Steps_Disabled ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1", Enabled = false };
+        WizardStep step2 = new () { Title = "Step 2", Enabled = false };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+
+        // Act
+        WizardStep? result = wizard.GetLastStep ();
+
+        // Assert
+        Assert.Null (result);
+    }
+
+    #endregion GetLastStep Tests
+
+    #region GetNextStep Tests
+
+    [Fact]
+    public void GetNextStep_Returns_Null_When_No_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+
+        // Act
+        WizardStep? result = wizard.GetNextStep ();
+
+        // Assert
+        Assert.Null (result);
+    }
+
+    [Fact]
+    public void GetNextStep_Returns_First_Step_When_CurrentStep_Is_Null ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+
+        // Act
+        WizardStep? result = wizard.GetNextStep ();
+
+        // Assert
+        Assert.Equal (step1, result);
+    }
+
+    [Fact]
+    public void GetNextStep_Returns_Next_Enabled_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        WizardStep? result = wizard.GetNextStep ();
+
+        // Assert
+        Assert.Equal (step2, result);
+    }
+
+    [Fact]
+    public void GetNextStep_Skips_Disabled_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2", Enabled = false };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        WizardStep? result = wizard.GetNextStep ();
+
+        // Assert
+        Assert.Equal (step3, result);
+    }
+
+    [Fact]
+    public void GetNextStep_Returns_Null_When_At_Last_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+        wizard.CurrentStep = step2;
+
+        // Act
+        WizardStep? result = wizard.GetNextStep ();
+
+        // Assert
+        Assert.Null (result);
+    }
+
+    [Fact]
+    public void GetNextStep_Returns_Null_When_All_Remaining_Steps_Disabled ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2", Enabled = false };
+        WizardStep step3 = new () { Title = "Step 3", Enabled = false };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        WizardStep? result = wizard.GetNextStep ();
+
+        // Assert
+        Assert.Null (result);
+    }
+
+    #endregion GetNextStep Tests
+
+    #region GetPreviousStep Tests
+
+    [Fact]
+    public void GetPreviousStep_Returns_Null_When_No_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+
+        // Act
+        WizardStep? result = wizard.GetPreviousStep ();
+
+        // Assert
+        Assert.Null (result);
+    }
+
+    [Fact]
+    public void GetPreviousStep_Returns_Last_Step_When_CurrentStep_Is_Null ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+
+        // Act
+        WizardStep? result = wizard.GetPreviousStep ();
+
+        // Assert
+        Assert.Equal (step2, result);
+    }
+
+    [Fact]
+    public void GetPreviousStep_Returns_Previous_Enabled_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+        wizard.CurrentStep = step3;
+
+        // Act
+        WizardStep? result = wizard.GetPreviousStep ();
+
+        // Assert
+        Assert.Equal (step2, result);
+    }
+
+    [Fact]
+    public void GetPreviousStep_Skips_Disabled_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2", Enabled = false };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+        wizard.CurrentStep = step3;
+
+        // Act
+        WizardStep? result = wizard.GetPreviousStep ();
+
+        // Assert
+        Assert.Equal (step1, result);
+    }
+
+    [Fact]
+    public void GetPreviousStep_Returns_Null_When_At_First_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        WizardStep? result = wizard.GetPreviousStep ();
+
+        // Assert
+        Assert.Null (result);
+    }
+
+    [Fact]
+    public void GetPreviousStep_Returns_Null_When_All_Previous_Steps_Disabled ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1", Enabled = false };
+        WizardStep step2 = new () { Title = "Step 2", Enabled = false };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        WizardStep? result = wizard.GetPreviousStep ();
+
+        // Assert
+        Assert.Null (result);
+    }
+
+    #endregion GetPreviousStep Tests
+
+    #region GoToStep Tests
+
+    [Fact]
+    public void GoToStep_Sets_CurrentStep ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        bool result = wizard.GoToStep (step2);
+
+        // Assert
+        Assert.True (result);
+        Assert.Equal (step2, wizard.CurrentStep);
+    }
+
+    [Fact]
+    public void GoToStep_Hides_Other_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        wizard.GoToStep (step2);
+
+        // Assert
+        Assert.False (step1.Visible);
+        Assert.True (step2.Visible);
+        Assert.False (step3.Visible);
+    }
+
+    [Fact]
+    public void GoToStep_Raises_StepChanging_Event ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        var eventRaised = false;
+        WizardStep? oldStep = null;
+        WizardStep? newStep = null;
+
+        wizard.StepChanging += (sender, args) =>
+                               {
+                                   eventRaised = true;
+                                   oldStep = args.CurrentValue;
+                                   newStep = args.NewValue;
+                               };
+
+        // Act
+        wizard.GoToStep (step2);
+
+        // Assert
+        Assert.True (eventRaised);
+        Assert.Equal (step1, oldStep);
+        Assert.Equal (step2, newStep);
+    }
+
+    [Fact]
+    public void GoToStep_Raises_StepChanged_Event ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+
+        var eventRaised = false;
+        WizardStep? newStep = null;
+
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Subscribe after EndInit to avoid capturing the initial CurrentStep setting
+        wizard.StepChanged += (sender, args) =>
+                              {
+                                  eventRaised = true;
+                                  newStep = args.NewValue;
+                              };
+
+        // Act
+        wizard.GoToStep (step2);
+
+        // Assert
+        Assert.True (eventRaised);
+        Assert.Same (step2, newStep);
+    }
+
+    [Fact]
+    public void GoToStep_Can_Be_Cancelled_Via_StepChanging_Event ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        wizard.StepChanging += (sender, args) => { args.Handled = true; };
+
+        // Act
+        bool result = wizard.GoToStep (step2);
+
+        // Assert
+        Assert.False (result);
+        Assert.Equal (step1, wizard.CurrentStep);
+    }
+
+    #endregion GoToStep Tests
+
+    #region GoNext Tests
+
+    [Fact]
+    public void GoNext_Moves_To_Next_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        bool result = wizard.GoNext ();
+
+        // Assert
+        Assert.True (result);
+        Assert.Equal (step2, wizard.CurrentStep);
+    }
+
+    [Fact]
+    public void GoNext_Returns_False_When_No_Next_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        wizard.AddStep (step1);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        bool result = wizard.GoNext ();
+
+        // Assert
+        Assert.False (result);
+        Assert.Equal (step1, wizard.CurrentStep);
+    }
+
+    [Fact]
+    public void GoNext_Skips_Disabled_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2", Enabled = false };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        bool result = wizard.GoNext ();
+
+        // Assert
+        Assert.True (result);
+        Assert.Equal (step3, wizard.CurrentStep);
+    }
+
+    #endregion GoNext Tests
+
+    #region GoBack Tests
+
+    [Fact]
+    public void GoBack_Moves_To_Previous_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+        wizard.CurrentStep = step2;
+
+        // Act
+        bool result = wizard.GoBack ();
+
+        // Assert
+        Assert.True (result);
+        Assert.Equal (step1, wizard.CurrentStep);
+    }
+
+    [Fact]
+    public void GoBack_Returns_False_When_No_Previous_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        wizard.AddStep (step1);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        bool result = wizard.GoBack ();
+
+        // Assert
+        Assert.False (result);
+        Assert.Equal (step1, wizard.CurrentStep);
+    }
+
+    [Fact]
+    public void GoBack_Skips_Disabled_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2", Enabled = false };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+        wizard.CurrentStep = step3;
+
+        // Act
+        bool result = wizard.GoBack ();
+
+        // Assert
+        Assert.True (result);
+        Assert.Equal (step1, wizard.CurrentStep);
+    }
+
+    #endregion GoBack Tests
+
+    #region CurrentStep Tests
+
+    [Fact]
+    public void CurrentStep_Setter_Calls_GoToStep ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        wizard.CurrentStep = step2;
+
+        // Assert
+        Assert.Equal (step2, wizard.CurrentStep);
+    }
+
+    [Fact]
+    public void CurrentStep_Can_Be_Set_To_Null ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        wizard.AddStep (step1);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        wizard.CurrentStep = null;
+
+        // Assert
+        Assert.Null (wizard.CurrentStep);
+    }
+
+    #endregion CurrentStep Tests
+
+    #region Title Tests
+
+    [Fact]
+    public void Title_Updates_With_Wizard_And_Step_Title ()
+    {
+        // Arrange
+        Wizard wizard = new () { Title = "Setup" };
+        WizardStep step1 = new () { Title = "Step 1" };
+        wizard.AddStep (step1);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act & Assert
+        Assert.Contains ("Setup", wizard.Title);
+        Assert.Contains ("Step 1", wizard.Title);
+    }
+
+    [Fact]
+    public void Title_Updates_When_Step_Changes ()
+    {
+        // Arrange
+        Wizard wizard = new () { Title = "Setup" };
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        wizard.GoNext ();
+
+        // Assert
+        Assert.Contains ("Step 2", wizard.Title);
+        Assert.DoesNotContain ("Step 1", wizard.Title);
+    }
+
+    #endregion Title Tests
+
+    #region Button Visibility Tests
+
+    [Fact]
+    public void BackButton_Not_Visible_On_First_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act & Assert
+        Assert.False (wizard.BackButton.Visible);
+    }
+
+    [Fact]
+    public void BackButton_Visible_On_Non_First_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        wizard.GoNext ();
+
+        // Assert
+        Assert.True (wizard.BackButton.Visible);
+    }
+
+    [Fact]
+    public void NextFinishButton_Shows_Next_On_Non_Last_Steps ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act & Assert
+        Assert.Equal (Strings.wzNext, wizard.NextFinishButton.Text);
+    }
+
+    [Fact]
+    public void NextFinishButton_Shows_Finish_On_Last_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        wizard.GoNext ();
+
+        // Assert
+        Assert.Equal (Strings.wzFinish, wizard.NextFinishButton.Text);
+    }
+
+    #endregion Button Visibility Tests
+
+    #region Custom Button Text Tests
+
+    [Fact]
+    public void BackButton_Uses_Custom_Text_From_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2", BackButtonText = "Go Back" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act
+        wizard.GoNext ();
+
+        // Assert
+        Assert.Equal ("Go Back", wizard.BackButton.Text);
+    }
+
+    [Fact]
+    public void NextFinishButton_Uses_Custom_Text_From_Step ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1", NextButtonText = "Proceed" };
+        wizard.AddStep (step1);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act & Assert
+        Assert.Equal ("Proceed", wizard.NextFinishButton.Text);
+    }
+
+    #endregion Custom Button Text Tests
+
+    #region Event Tests
+
+    [Fact]
+    public void MovingNext_Event_Raised_When_Next_Button_Clicked ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        var eventRaised = false;
+        wizard.MovingNext += (sender, args) => { eventRaised = true; };
+
+        // Act
+        wizard.NextFinishButton.InvokeCommand (Command.Accept);
+
+        // Assert
+        Assert.True (eventRaised);
+    }
+
+    [Fact]
+    public void MovingBack_Event_Raised_When_Back_Button_Clicked ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+        wizard.GoNext ();
+
+        var eventRaised = false;
+        wizard.MovingBack += (sender, args) => { eventRaised = true; };
+
+        // Act
+        wizard.BackButton.InvokeCommand (Command.Accept);
+
+        // Assert
+        Assert.True (eventRaised);
+    }
+
+    #endregion Event Tests
+
+    #region Enabled State Tests
+
+    [Fact]
+    public void Disabling_Step_Updates_Navigation ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2" };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act - Disable middle step
+        step2.Enabled = false;
+
+        // Assert - GetNextStep from step1 should skip to step3
+        WizardStep? nextStep = wizard.GetNextStep ();
+        Assert.Equal (step3, nextStep);
+    }
+
+    [Fact]
+    public void Enabling_Step_Updates_Navigation ()
+    {
+        // Arrange
+        Wizard wizard = new ();
+        WizardStep step1 = new () { Title = "Step 1" };
+        WizardStep step2 = new () { Title = "Step 2", Enabled = false };
+        WizardStep step3 = new () { Title = "Step 3" };
+        wizard.AddStep (step1);
+        wizard.AddStep (step2);
+        wizard.AddStep (step3);
+        wizard.BeginInit ();
+        wizard.EndInit ();
+
+        // Act - Enable middle step
+        step2.Enabled = true;
+
+        // Assert - GetNextStep from step1 should now return step2
+        WizardStep? nextStep = wizard.GetNextStep ();
+        Assert.Equal (step2, nextStep);
+    }
+
+    #endregion Enabled State Tests
+}