浏览代码

Merge branch 'v2_develop' into copilot/fix-e6dde989-9ea1-4d83-8522-54ed8f70815a

Tig 1 周之前
父节点
当前提交
98ae6314be
共有 100 个文件被更改,包括 4829 次插入5445 次删除
  1. 5 0
      .config/dotnet-tools.json
  2. 3 3
      .editorconfig
  3. 79 0
      .github/workflows/README.md
  4. 3 21
      .github/workflows/build-validation.yml
  5. 77 36
      .github/workflows/integration-tests.yml
  6. 43 0
      .github/workflows/quick-build.yml
  7. 151 27
      .github/workflows/unit-tests.yml
  8. 6 0
      .gitignore
  9. 36 159
      CONTRIBUTING.md
  10. 1 1
      Directory.Packages.props
  11. 0 2
      Examples/CommunityToolkitExample/LoginView.cs
  12. 4 4
      Examples/CommunityToolkitExample/LoginViewModel.cs
  13. 0 1
      Examples/CommunityToolkitExample/Message.cs
  14. 7 8
      Examples/CommunityToolkitExample/Program.cs
  15. 25 21
      Examples/CommunityToolkitExample/README.md
  16. 27 36
      Examples/Example/Example.cs
  17. 1 4
      Examples/Example/README.md
  18. 11 0
      Examples/FluentExample/FluentExample.csproj
  19. 109 0
      Examples/FluentExample/Program.cs
  20. 4 4
      Examples/NativeAot/Program.cs
  21. 7 8
      Examples/ReactiveExample/Program.cs
  22. 8 4
      Examples/ReactiveExample/README.md
  23. 28 21
      Examples/ReactiveExample/TerminalScheduler.cs
  24. 1 2
      Examples/ReactiveExample/ViewExtensions.cs
  25. 168 0
      Examples/RunnableWrapperExample/Program.cs
  26. 15 0
      Examples/RunnableWrapperExample/RunnableWrapperExample.csproj
  27. 16 16
      Examples/SelfContained/Program.cs
  28. 26 0
      Examples/SelfContained/README.md
  29. 1 1
      Examples/UICatalog/README.md
  30. 6 7
      Examples/UICatalog/Resources/config.json
  31. 16 21
      Examples/UICatalog/Scenario.cs
  32. 20 20
      Examples/UICatalog/Scenarios/Adornments.cs
  33. 15 12
      Examples/UICatalog/Scenarios/AllViewsTester.cs
  34. 2 2
      Examples/UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs
  35. 62 59
      Examples/UICatalog/Scenarios/AnsiRequestsScenario.cs
  36. 4 4
      Examples/UICatalog/Scenarios/Arrangement.cs
  37. 23 23
      Examples/UICatalog/Scenarios/Bars.cs
  38. 27 54
      Examples/UICatalog/Scenarios/Buttons.cs
  39. 12 36
      Examples/UICatalog/Scenarios/CharacterMap/CharacterMap.cs
  40. 3 2
      Examples/UICatalog/Scenarios/ChineseUI.cs
  41. 210 188
      Examples/UICatalog/Scenarios/ClassExplorer.cs
  42. 2 2
      Examples/UICatalog/Scenarios/Clipping.cs
  43. 169 112
      Examples/UICatalog/Scenarios/CollectionNavigatorTester.cs
  44. 47 16
      Examples/UICatalog/Scenarios/ColorPicker.cs
  45. 17 6
      Examples/UICatalog/Scenarios/CombiningMarks.cs
  46. 3 3
      Examples/UICatalog/Scenarios/ComboBoxIteration.cs
  47. 1 1
      Examples/UICatalog/Scenarios/ComputedLayout.cs
  48. 5 5
      Examples/UICatalog/Scenarios/ConfigurationEditor.cs
  49. 77 69
      Examples/UICatalog/Scenarios/ContextMenus.cs
  50. 270 211
      Examples/UICatalog/Scenarios/CsvEditor.cs
  51. 14 11
      Examples/UICatalog/Scenarios/Dialogs.cs
  52. 5 5
      Examples/UICatalog/Scenarios/DimAutoDemo.cs
  53. 0 1413
      Examples/UICatalog/Scenarios/DynamicMenuBar.cs
  54. 27 14
      Examples/UICatalog/Scenarios/DynamicStatusBar.cs
  55. 504 677
      Examples/UICatalog/Scenarios/Editor.cs
  56. 3 3
      Examples/UICatalog/Scenarios/EditorsAndHelpers/AdornmentsEditor.cs
  57. 39 17
      Examples/UICatalog/Scenarios/EditorsAndHelpers/AllViewsView.cs
  58. 14 80
      Examples/UICatalog/Scenarios/EditorsAndHelpers/ArrangementEditor.cs
  59. 14 13
      Examples/UICatalog/Scenarios/EditorsAndHelpers/BorderEditor.cs
  60. 10 10
      Examples/UICatalog/Scenarios/EditorsAndHelpers/DimEditor.cs
  61. 14 22
      Examples/UICatalog/Scenarios/EditorsAndHelpers/MarginEditor.cs
  62. 10 10
      Examples/UICatalog/Scenarios/EditorsAndHelpers/PosEditor.cs
  63. 9 10
      Examples/UICatalog/Scenarios/EditorsAndHelpers/ViewPropertiesEditor.cs
  64. 134 134
      Examples/UICatalog/Scenarios/FileDialogExamples.cs
  65. 1 1
      Examples/UICatalog/Scenarios/Generic.cs
  66. 303 343
      Examples/UICatalog/Scenarios/GraphViewExample.cs
  67. 9 9
      Examples/UICatalog/Scenarios/HexEditor.cs
  68. 20 20
      Examples/UICatalog/Scenarios/Images.cs
  69. 71 43
      Examples/UICatalog/Scenarios/InteractiveTree.cs
  70. 4 4
      Examples/UICatalog/Scenarios/KeyBindings.cs
  71. 5 8
      Examples/UICatalog/Scenarios/Keys.cs
  72. 4 4
      Examples/UICatalog/Scenarios/LineCanvasExperiment.cs
  73. 11 5
      Examples/UICatalog/Scenarios/LineDrawing.cs
  74. 309 268
      Examples/UICatalog/Scenarios/ListColumns.cs
  75. 5 5
      Examples/UICatalog/Scenarios/ListViewWithSelection.cs
  76. 3 3
      Examples/UICatalog/Scenarios/ListsAndCombos.cs
  77. 92 77
      Examples/UICatalog/Scenarios/Localization.cs
  78. 8 8
      Examples/UICatalog/Scenarios/Mazing.cs
  79. 0 135
      Examples/UICatalog/Scenarios/MenuBarScenario.cs
  80. 6 6
      Examples/UICatalog/Scenarios/Menus.cs
  81. 18 17
      Examples/UICatalog/Scenarios/MessageBoxes.cs
  82. 2 2
      Examples/UICatalog/Scenarios/Mouse.cs
  83. 82 73
      Examples/UICatalog/Scenarios/MultiColouredTable.cs
  84. 17 15
      Examples/UICatalog/Scenarios/Navigation.cs
  85. 166 119
      Examples/UICatalog/Scenarios/Notepad.cs
  86. 2 2
      Examples/UICatalog/Scenarios/NumericUpDownDemo.cs
  87. 146 140
      Examples/UICatalog/Scenarios/PosAlignDemo.cs
  88. 1 1
      Examples/UICatalog/Scenarios/Progress.cs
  89. 31 21
      Examples/UICatalog/Scenarios/ProgressBarStyles.cs
  90. 37 64
      Examples/UICatalog/Scenarios/RegionScenario.cs
  91. 4 4
      Examples/UICatalog/Scenarios/RunTExample.cs
  92. 177 74
      Examples/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs
  93. 5 9
      Examples/UICatalog/Scenarios/ScrollBarDemo.cs
  94. 15 15
      Examples/UICatalog/Scenarios/Scrolling.cs
  95. 287 0
      Examples/UICatalog/Scenarios/Selectors.cs
  96. 127 90
      Examples/UICatalog/Scenarios/Shortcuts.cs
  97. 126 117
      Examples/UICatalog/Scenarios/SingleBackgroundWorker.cs
  98. 9 9
      Examples/UICatalog/Scenarios/Sliders.cs
  99. 18 18
      Examples/UICatalog/Scenarios/SpinnerStyles.cs
  100. 58 65
      Examples/UICatalog/Scenarios/SyntaxHighlighting.cs

+ 5 - 0
.config/dotnet-tools.json

@@ -0,0 +1,5 @@
+{
+  "version": 1,
+  "isRoot": true,
+  "tools": {}
+}

+ 3 - 3
.editorconfig

@@ -82,8 +82,8 @@ dotnet_diagnostic.cs0464.severity = warning
 dotnet_diagnostic.cs0465.severity = warning
 dotnet_diagnostic.cs0469.severity = warning
 dotnet_diagnostic.cs0472.severity = warning
-dotnet_diagnostic.cs0612.severity = warning
-dotnet_diagnostic.cs0618.severity = warning
+dotnet_diagnostic.cs0612.severity = none
+dotnet_diagnostic.cs0618.severity = none
 dotnet_diagnostic.cs0628.severity = warning
 dotnet_diagnostic.cs0642.severity = warning
 dotnet_diagnostic.cs0649.severity = warning
@@ -94,7 +94,7 @@ dotnet_diagnostic.cs0659.severity = warning
 dotnet_diagnostic.cs0660.severity = warning
 dotnet_diagnostic.cs0661.severity = warning
 dotnet_diagnostic.cs0665.severity = warning
-dotnet_diagnostic.cs0672.severity = warning
+dotnet_diagnostic.cs0672.severity = none
 dotnet_diagnostic.cs0675.severity = warning
 dotnet_diagnostic.cs0693.severity = warning
 dotnet_diagnostic.cs0728.severity = warning

+ 79 - 0
.github/workflows/README.md

@@ -0,0 +1,79 @@
+## CI/CD Workflows
+
+The repository uses multiple GitHub Actions workflows. What runs and when:
+
+### 1) Build Solution (`.github/workflows/build.yml`)
+
+- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`); supports `workflow_call`
+- **Runner/timeout**: `ubuntu-latest`, 10 minutes
+- **Steps**:
+- Checkout and setup .NET 8.x GA
+- `dotnet restore`
+- Build Debug: `dotnet build --configuration Debug --no-restore -property:NoWarn=0618%3B0612`
+- Build Release (library): `dotnet build Terminal.Gui/Terminal.Gui.csproj --configuration Release --no-incremental --force -property:NoWarn=0618%3B0612`
+- Pack Release: `dotnet pack Terminal.Gui/Terminal.Gui.csproj --configuration Release --output ./local_packages -property:NoWarn=0618%3B0612`
+- Restore NativeAot/SelfContained examples, then restore solution again
+- Build Release for `Examples/NativeAot` and `Examples/SelfContained`
+- Build Release solution
+- Upload artifacts named `build-artifacts`, retention 1 day
+
+### 2) Build & Run Unit Tests (`.github/workflows/unit-tests.yml`)
+
+- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
+- **Matrix**: Ubuntu/Windows/macOS
+- **Timeout**: 15 minutes per job
+- **Process**:
+1. Calls build workflow to build solution once
+2. Downloads build artifacts
+3. Runs `dotnet restore` (required for `--no-build` to work)
+4. **Performance optimizations**:
+   - Disables Windows Defender on Windows runners (significant speedup)
+   - Collects code coverage **only on Linux** (ubuntu-latest) for performance
+   - Windows and macOS skip coverage collection to reduce test time
+   - Increased blame-hang-timeout to 120s for Windows/macOS (60s for Linux)
+5. Runs two test jobs:
+   - **Non-parallel UnitTests**: `Tests/UnitTests` with blame/diag flags; `xunit.stopOnFail=false`
+   - **Parallel UnitTestsParallelizable**: `Tests/UnitTestsParallelizable` with blame/diag flags; `xunit.stopOnFail=false`
+6. Uploads test logs and diagnostic data from all runners
+7. **Uploads code coverage to Codecov only from Linux runner**
+
+**Test results**: All tests output to unified `TestResults/` directory at repository root
+
+### 3) Build & Run Integration Tests (`.github/workflows/integration-tests.yml`)
+
+- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
+- **Matrix**: Ubuntu/Windows/macOS
+- **Timeout**: 15 minutes
+- **Process**:
+1. Calls build workflow
+2. Downloads build artifacts
+3. Runs `dotnet restore`
+4. **Performance optimizations** (same as unit tests):
+   - Disables Windows Defender on Windows runners
+   - Collects code coverage **only on Linux**
+   - Increased blame-hang-timeout to 120s for Windows/macOS
+5. Runs IntegrationTests with blame/diag flags; `xunit.stopOnFail=true`
+6. Uploads logs per-OS
+7. **Uploads coverage to Codecov only from Linux runner**
+
+### 4) Publish to NuGet (`.github/workflows/publish.yml`)
+
+- **Triggers**: push to `v2_release`, `v2_develop`, and tags `v*`(ignores `**.md`)
+- Uses GitVersion to compute SemVer, builds Release, packs with symbols, and pushes to NuGet.org using `NUGET_API_KEY`
+
+### 5) Build and publish API docs (`.github/workflows/api-docs.yml`)
+
+- **Triggers**: push to `v1_release` and `v2_develop`
+- Builds DocFX site on Windows and deploys to GitHub Pages when `ref_name` is `v2_release` or `v2_develop`
+
+
+### Replicating CI Locally
+
+```bash
+# Full CI sequence:
+dotnet restore
+dotnet build --configuration Debug --no-restore
+dotnet test Tests/UnitTests --no-build --verbosity normal
+dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal
+dotnet build --configuration Release --no-restore
+```

+ 3 - 21
.github/workflows/build.yml → .github/workflows/build-validation.yml

@@ -1,4 +1,4 @@
-name: Build Solution
+name: Build Validation
 
 on:
   push:
@@ -9,18 +9,11 @@ on:
     branches: [ v2_release, v2_develop ]
     paths-ignore:
       - '**.md'
-  workflow_call:
-    outputs:
-      artifact-name:
-        description: "Name of the build artifacts"
-        value: ${{ jobs.build.outputs.artifact-name }}
       
 jobs:
-  build:
-    name: Build Debug & Release
+  build-validation:
+    name: Build All Configurations
     runs-on: ubuntu-latest
-    outputs:
-      artifact-name: build-artifacts
     
     timeout-minutes: 10
     steps:
@@ -63,14 +56,3 @@ jobs:
 
     - name: Build Release Solution
       run: dotnet build --configuration Release --no-restore -property:NoWarn=0618%3B0612
-
-    - name: Upload build artifacts
-      uses: actions/upload-artifact@v4
-      with:
-        name: build-artifacts
-        path: |
-          **/bin/Debug/**
-          **/obj/Debug/**
-          **/bin/Release/**
-          **/obj/Release/**
-        retention-days: 1

+ 77 - 36
.github/workflows/integration-tests.yml

@@ -1,5 +1,4 @@
 name: Build & Run Integration Tests
-
 on:
   push:
     branches: [ v2_release, v2_develop ]
@@ -9,57 +8,99 @@ on:
     branches: [ v2_release, v2_develop ]
     paths-ignore:
       - '**.md'
-      
+
 jobs:
-  # Call the build workflow to build the solution once
   build:
-    uses: ./.github/workflows/build.yml
+    uses: ./.github/workflows/quick-build.yml
 
   integration_tests:
     name: Integration Tests
     runs-on: ${{ matrix.os }}
     needs: build
     strategy:
-      # Turn off fail-fast to let all runners run even if there are errors
-      fail-fast: true
+      fail-fast: false  # Let all OSes finish even if one fails
       matrix:
         os: [ ubuntu-latest, windows-latest, macos-latest ]
+    timeout-minutes: 15
 
-    timeout-minutes: 10
     steps:
+      - name: Checkout code
+        uses: actions/checkout@v4
+
+      - name: Setup .NET Core
+        uses: actions/setup-dotnet@v4
+        with:
+          dotnet-version: 8.x
+          dotnet-quality: ga
+
+      - name: Download build artifacts
+        uses: actions/download-artifact@v4
+        with:
+          name: test-build-artifacts
+          path: .
 
-    - name: Checkout code
-      uses: actions/checkout@v4
+      - name: Restore NuGet packages
+        run: dotnet restore
 
-    - name: Setup .NET Core
-      uses: actions/setup-dotnet@v4
-      with:
-        dotnet-version: 8.x
-        dotnet-quality: 'ga'
+      - name: Disable Windows Defender (Windows only)
+        if: runner.os == 'Windows'
+        shell: powershell
+        run: |
+          Add-MpPreference -ExclusionPath "${{ github.workspace }}"
+          Add-MpPreference -ExclusionProcess "dotnet.exe"
+          Add-MpPreference -ExclusionProcess "testhost.exe"
+          Add-MpPreference -ExclusionProcess "VSTest.Console.exe"
 
-    - name: Download build artifacts
-      uses: actions/download-artifact@v4
-      with:
-        name: build-artifacts
-        path: .
+      - name: Set VSTEST_DUMP_PATH
+        shell: bash
+        run: echo "VSTEST_DUMP_PATH=logs/IntegrationTests/${{ runner.os }}/" >> $GITHUB_ENV
 
-    - name: Restore NuGet packages
-      run: dotnet restore
+      - name: Run IntegrationTests
+        shell: bash
+        run: |
+          if [ "${{ runner.os }}" == "Linux" ]; then
+            # Run with coverage on Linux only
+            dotnet test Tests/IntegrationTests \
+              --no-build \
+              --verbosity minimal \
+              --collect:"XPlat Code Coverage" \
+              --settings Tests/IntegrationTests/runsettings.coverage.xml \
+              --diag:logs/IntegrationTests/${{ runner.os }}/logs.txt \
+              --blame \
+              --blame-crash \
+              --blame-hang \
+              --blame-hang-timeout 60s \
+              --blame-crash-collect-always
+          else
+            # Run without coverage on Windows/macOS for speed
+            dotnet test Tests/IntegrationTests \
+              --no-build \
+              --verbosity minimal \
+              --settings Tests/IntegrationTests/runsettings.xml \
+              --diag:logs/IntegrationTests/${{ runner.os }}/logs.txt \
+              --blame \
+              --blame-crash \
+              --blame-hang \
+              --blame-hang-timeout 60s \
+              --blame-crash-collect-always
+          fi
 
-    - name: Set VSTEST_DUMP_PATH
-      shell: bash
-      run: echo "{VSTEST_DUMP_PATH}={logs/${{ runner.os }}/}" >> $GITHUB_ENV
+      - name: Upload Integration Test Logs
+        if: always()
+        uses: actions/upload-artifact@v4
+        with:
+          name: integration_tests-logs-${{ runner.os }}
+          path: |
+            logs/IntegrationTests/
+            TestResults/
 
-    - name: Run IntegrationTests
-      run: |
-       dotnet test Tests/IntegrationTests --no-build --verbosity normal --diag:logs/${{ runner.os }}/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always -- xunit.stopOnFail=true
-     
-    - name: Upload Test Logs
-      if: always()
-      uses: actions/upload-artifact@v4
-      with:
-        name: integration-test-logs-${{ runner.os }}
-        path: |
-          logs/    
-          TestResults/IntegrationTests/
+      - name: Upload Integration Tests Coverage to Codecov
+        if: matrix.os == 'ubuntu-latest' && always()
+        uses: codecov/codecov-action@v4
+        with:
+          files: TestResults/**/coverage.cobertura.xml
+          flags: integrationtests
+          name: IntegrationTests-${{ runner.os }}
+          token: ${{ secrets.CODECOV_TOKEN }}
+          fail_ci_if_error: false
 

+ 43 - 0
.github/workflows/quick-build.yml

@@ -0,0 +1,43 @@
+name: Quick Build for Tests
+
+on:
+  workflow_call:
+    outputs:
+      artifact-name:
+        description: "Name of the build artifacts"
+        value: ${{ jobs.quick-build.outputs.artifact-name }}
+      
+jobs:
+  quick-build:
+    name: Build Debug Only
+    runs-on: ubuntu-latest
+    outputs:
+      artifact-name: test-build-artifacts
+    
+    timeout-minutes: 5
+    steps:
+
+    - name: Checkout code
+      uses: actions/checkout@v4
+
+    - name: Setup .NET Core
+      uses: actions/setup-dotnet@v4
+      with:
+        dotnet-version: 8.x
+        dotnet-quality: 'ga'
+
+    - name: Restore dependencies
+      run: dotnet restore
+
+    # Suppress CS0618 (member is obsolete) and CS0612 (member is obsolete without message)
+    - name: Build Debug
+      run: dotnet build --configuration Debug --no-restore -property:NoWarn=0618%3B0612
+
+    - name: Upload build artifacts
+      uses: actions/upload-artifact@v4
+      with:
+        name: test-build-artifacts
+        path: |
+          **/bin/Debug/**
+          **/obj/Debug/**
+        retention-days: 1

+ 151 - 27
.github/workflows/unit-tests.yml

@@ -11,9 +11,9 @@ on:
       - '**.md'
       
 jobs:
-  # Call the build workflow to build the solution once
+  # Call the quick-build workflow to build Debug configuration only
   build:
-    uses: ./.github/workflows/build.yml
+    uses: ./.github/workflows/quick-build.yml
 
   non_parallel_unittests:
     name: Non-Parallel Unit Tests  
@@ -21,11 +21,11 @@ jobs:
     needs: build
     strategy:
       # Turn off fail-fast to let all runners run even if there are errors
-      fail-fast: true
+      fail-fast: false
       matrix:
         os: [ ubuntu-latest, windows-latest, macos-latest ]
 
-    timeout-minutes: 10
+    timeout-minutes: 15  # Increased from 10 for Windows
     steps:
 
     - name: Checkout code
@@ -40,26 +40,56 @@ jobs:
     - name: Download build artifacts
       uses: actions/download-artifact@v4
       with:
-        name: build-artifacts
+        name: test-build-artifacts
         path: .
 
+    # KEEP THIS - It's needed for --no-build to work
     - name: Restore NuGet packages
       run: dotnet restore
 
-# Test
-    # Note: The --blame and VSTEST_DUMP_PATH stuff is needed to diagnose the test runner crashing on ubuntu/mac
-    # See https://github.com/microsoft/vstest/issues/2952 for why the --blame stuff below is needed.
-    # Without it, the test runner crashes on ubuntu (but not Windows or mac)
+    # Optimize Windows performance
+    - name: Disable Windows Defender (Windows only)
+      if: runner.os == 'Windows'
+      shell: powershell
+      run: |
+        Add-MpPreference -ExclusionPath "${{ github.workspace }}"
+        Add-MpPreference -ExclusionProcess "dotnet.exe"
+        Add-MpPreference -ExclusionProcess "testhost.exe"
+        Add-MpPreference -ExclusionProcess "VSTest.Console.exe"
 
     - name: Set VSTEST_DUMP_PATH
       shell: bash
-      run: echo "{VSTEST_DUMP_PATH}={logs/UnitTests/${{ runner.os }}/}" >> $GITHUB_ENV
+      run: echo "VSTEST_DUMP_PATH=logs/UnitTests/${{ runner.os }}/" >> $GITHUB_ENV
 
     - name: Run UnitTests
+      shell: bash
       run: |
-       dotnet test Tests/UnitTests --no-build --verbosity normal --collect:"XPlat Code Coverage" --settings Tests/UnitTests/coverlet.runsettings --diag:logs/UnitTests/${{ runner.os }}/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always -- xunit.stopOnFail=false
-     
-       # mv -v Tests/UnitTests/TestResults/*/*.* TestResults/UnitTests/
+        if [ "${{ runner.os }}" == "Linux" ]; then
+          # Run with coverage on Linux only
+          dotnet test Tests/UnitTests \
+            --no-build \
+            --verbosity normal \
+            --collect:"XPlat Code Coverage" \
+            --settings Tests/UnitTests/runsettings.xml \
+            --diag:logs/UnitTests/${{ runner.os }}/logs.txt \
+            --blame \
+            --blame-crash \
+            --blame-hang \
+            --blame-hang-timeout 60s \
+            --blame-crash-collect-always
+        else
+          # Run without coverage on Windows/macOS for speed
+          dotnet test Tests/UnitTests \
+            --no-build \
+            --verbosity normal \
+            --settings Tests/UnitTests/runsettings.xml \
+            --diag:logs/UnitTests/${{ runner.os }}/logs.txt \
+            --blame \
+            --blame-crash \
+            --blame-hang \
+            --blame-hang-timeout 120s \
+            --blame-crash-collect-always
+        fi
 
     - name: Upload Test Logs
       if: always()
@@ -68,19 +98,29 @@ jobs:
         name: non_parallel_unittests-logs-${{ runner.os }}
         path: |
           logs/UnitTests    
-          TestResults/UnitTests/
+          TestResults/
   
+    - name: Upload Non-Parallel UnitTests Coverage to Codecov
+      if: matrix.os == 'ubuntu-latest' && always()
+      uses: codecov/codecov-action@v4
+      with:
+        files: TestResults/**/coverage.cobertura.xml
+        flags: unittests-nonparallel
+        name: UnitTests-${{ runner.os }}
+        token: ${{ secrets.CODECOV_TOKEN }}
+        fail_ci_if_error: false
+
   parallel_unittests:
     name: Parallel Unit Tests  
     runs-on: ${{ matrix.os }}
     needs: build
     strategy:
       # Turn off fail-fast to let all runners run even if there are errors
-      fail-fast: true
+      fail-fast: false
       matrix:
         os: [ ubuntu-latest, windows-latest, macos-latest ]
 
-    timeout-minutes: 10
+    timeout-minutes: 60
     steps:
 
     - name: Checkout code
@@ -95,26 +135,100 @@ jobs:
     - name: Download build artifacts
       uses: actions/download-artifact@v4
       with:
-        name: build-artifacts
+        name: test-build-artifacts
         path: .
 
     - name: Restore NuGet packages
       run: dotnet restore
 
-# Test
-    # Note: The --blame and VSTEST_DUMP_PATH stuff is needed to diagnose the test runner crashing on ubuntu/mac
-    # See https://github.com/microsoft/vstest/issues/2952 for why the --blame stuff below is needed.
-    # Without it, the test runner crashes on ubuntu (but not Windows or mac)
+    - name: Disable Windows Defender (Windows only)
+      if: runner.os == 'Windows'
+      shell: powershell
+      run: |
+        Add-MpPreference -ExclusionPath "${{ github.workspace }}"
+        Add-MpPreference -ExclusionProcess "dotnet.exe"
+        Add-MpPreference -ExclusionProcess "testhost.exe"
+        Add-MpPreference -ExclusionProcess "VSTest.Console.exe"
 
     - name: Set VSTEST_DUMP_PATH
       shell: bash
-      run: echo "{VSTEST_DUMP_PATH}={logs/UnitTestsParallelizable/${{ runner.os }}/}" >> $GITHUB_ENV
+      run: echo "VSTEST_DUMP_PATH=logs/UnitTestsParallelizable/${{ runner.os }}/" >> $GITHUB_ENV
 
-    - name: Run UnitTestsParallelizable
+    - name: Run UnitTestsParallelizable (10 iterations with varying parallelization)
+      shell: bash
       run: |
-       dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal --collect:"XPlat Code Coverage" --settings Tests/UnitTestsParallelizable/coverlet.runsettings --diag:logs/UnitTestsParallelizable/${{ runner.os }}/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always -- xunit.stopOnFail=false
-     
-       # mv -v Tests/UnitTestsParallelizable/TestResults/*/*.* TestResults/UnitTestsParallelizable/
+        # Run tests 3 times with different parallelization settings to expose concurrency issues
+        for RUN in {1..3}; do
+          echo "============================================"
+          echo "Starting test run $RUN of 3"
+          echo "============================================"
+          
+          # Use a combination of run number and timestamp to create different execution patterns
+          SEED=$((1000 + $RUN + $(date +%s) % 1000))
+          echo "Using randomization seed: $SEED"
+          
+          # Vary the xUnit parallelization based on run number to expose race conditions
+          # Runs 1-3: Default parallelization (2x CPU cores)
+          # Runs 4-6: Max parallelization (unlimited)
+          # Runs 7-9: Single threaded (1)
+          # Run 10: Random (1-4 threads)
+          if [ $RUN -le 3 ]; then
+            XUNIT_MAX_PARALLEL_THREADS="2x"
+            echo "Run $RUN: Using default parallelization (2x)"
+          elif [ $RUN -le 6 ]; then
+            XUNIT_MAX_PARALLEL_THREADS="unlimited"
+            echo "Run $RUN: Using maximum parallelization (unlimited)"
+          elif [ $RUN -le 9 ]; then
+            XUNIT_MAX_PARALLEL_THREADS="1"
+            echo "Run $RUN: Using single-threaded execution"
+          else
+            # Random parallelization based on seed
+            PROC_COUNT=$(( ($SEED % 4) + 1 ))
+            XUNIT_MAX_PARALLEL_THREADS="$PROC_COUNT"
+            echo "Run $RUN: Using random parallelization with $PROC_COUNT threads"
+          fi
+          
+          # Run tests with or without coverage based on OS and run number
+          if [ "${{ runner.os }}" == "Linux" ] && [ $RUN -eq 1 ]; then
+            echo "Run $RUN: Running with coverage collection"
+            dotnet test Tests/UnitTestsParallelizable \
+              --no-build \
+              --verbosity normal \
+              --collect:"XPlat Code Coverage" \
+              --settings Tests/UnitTests/runsettings.coverage.xml \
+              --diag:logs/UnitTestsParallelizable/${{ runner.os }}/run${RUN}-logs.txt \
+              --blame \
+              --blame-crash \
+              --blame-hang \
+              --blame-hang-timeout 60s \
+              --blame-crash-collect-always \
+              -- xUnit.MaxParallelThreads=${XUNIT_MAX_PARALLEL_THREADS}
+          else
+            dotnet test Tests/UnitTestsParallelizable \
+              --no-build \
+              --verbosity normal \
+              --settings Tests/UnitTestsParallelizable/runsettings.xml \
+              --diag:logs/UnitTestsParallelizable/${{ runner.os }}/run${RUN}-logs.txt \
+              --blame \
+              --blame-crash \
+              --blame-hang \
+              --blame-hang-timeout 60s \
+              --blame-crash-collect-always \
+              -- xUnit.MaxParallelThreads=${XUNIT_MAX_PARALLEL_THREADS}
+          fi
+          
+          if [ $? -ne 0 ]; then
+            echo "ERROR: Test run $RUN failed!"
+            exit 1
+          fi
+          
+          echo "Test run $RUN completed successfully"
+          echo ""
+        done
+        
+        echo "============================================"
+        echo "All 10 test runs completed successfully!"
+        echo "============================================"
 
     - name: Upload UnitTestsParallelizable Logs
       if: always()
@@ -123,4 +237,14 @@ jobs:
         name: parallel_unittests-logs-${{ runner.os }}
         path: |
           logs/UnitTestsParallelizable/
-          TestResults/UnitTestsParallelizable/
+          TestResults/
+  
+    - name: Upload Parallelizable UnitTests Coverage to Codecov
+      if: matrix.os == 'ubuntu-latest' && always()
+      uses: codecov/codecov-action@v4
+      with:
+        files: TestResults/**/coverage.cobertura.xml
+        flags: unittests-parallel
+        name: UnitTestsParallelizable-${{ runner.os }}
+        token: ${{ secrets.CODECOV_TOKEN }}
+        fail_ci_if_error: false

+ 6 - 0
.gitignore

@@ -68,3 +68,9 @@ BenchmarkDotNet.Artifacts/
 *.log.*
 
 log.*
+
+/Tests/coverage/
+!/Tests/coverage/.gitkeep   # keep folder in repo
+/Tests/report/
+*.cobertura.xml
+/docfx/docs/migratingfromv1.md

+ 36 - 159
CONTRIBUTING.md

@@ -7,34 +7,40 @@ Welcome! This guide provides everything you need to know to contribute effective
 ## Table of Contents
 
 - [Project Overview](#project-overview)
-- [Building and Testing](#building-and-testing)
+- [Key Architecture Concepts](#key-architecture-concepts)
 - [Coding Conventions](#coding-conventions)
+- [Building and Testing](#building-and-testing)
 - [Testing Requirements](#testing-requirements)
 - [API Documentation Requirements](#api-documentation-requirements)
 - [Pull Request Guidelines](#pull-request-guidelines)
 - [CI/CD Workflows](#cicd-workflows)
 - [Repository Structure](#repository-structure)
 - [Branching Model](#branching-model)
-- [Key Architecture Concepts](#key-architecture-concepts)
 - [What NOT to Do](#what-not-to-do)
-- [Additional Resources](#additional-resources)
-
----
 
 ## Project Overview
 
-**Terminal.Gui** is a cross-platform UI toolkit for creating console-based graphical user interfaces in .NET. It's a large codebase (~1,050 C# files, 333MB) providing a comprehensive framework for building interactive console applications with support for keyboard and mouse input, customizable views, and a robust event system.
+**Terminal.Gui** is a cross-platform UI toolkit for creating console-based graphical user interfaces in .NET. It's a large codebase (~1,050 C# files) providing a comprehensive framework for building interactive console applications with support for keyboard and mouse input, customizable views, and a robust event system.
 
 **Key characteristics:**
 - **Language**: C# (net8.0)
-- **Size**: ~496 source files in core library, ~1,050 total C# files
 - **Platform**: Cross-platform (Windows, macOS, Linux)
 - **Architecture**: Console UI toolkit with driver-based architecture
 - **Version**: v2 (Alpha), v1 (maintenance mode)
 - **Branching**: GitFlow model (v2_develop is default/active development)
 
----
+## Key Architecture Concepts
+
+**⚠️ CRITICAL - AI Agents MUST understand these concepts before starting work.**
 
+- **Application Lifecycle** - How `Application.Init`, `Application.Run`, and `Application.Shutdown` work - [Application Deep Dive](./docfx/docs/application.md)
+- **Cancellable Workflow Patern** - [CWP Deep Dive](./docfx/docs/cancellable-work-pattern.md)
+- **View Hierarchy** - Understanding `View`, `Runnable`, `Window`, and view containment - [View Deep Dive](./docfx/docs/View.md)
+- **Layout System** - Pos, Dim, and automatic layout -  [Layout System](./docfx/docs/layout.md)
+- **Event System** - How keyboard, mouse, and application events flow - [Events Deep Dive](./docfx/docs/events.md)
+- **Driver Architecture** - How console drivers abstract platform differences - [Drivers](./docfx/docs/drivers.md)
+- **Drawing Model** - How rendering works with Attributes, Colors, and Glyphs  - [Drawing Deep Dive](./docfx/docs/drivers.md)
+ 
 ## Building and Testing
 
 ### Required Tools
@@ -88,43 +94,20 @@ Welcome! This guide provides everything you need to know to contribute effective
    dotnet test Tests/IntegrationTests --no-build --verbosity normal
    ```
 
-**Important**: Tests may take significant time. CI uses blame flags for crash detection:
-```bash
---diag:logs/UnitTests/logs.txt --blame --blame-crash --blame-hang --blame-hang-timeout 60s --blame-crash-collect-always
-```
-
 ### Common Build Issues
 
-#### Issue: Build Warnings
-- **Expected**: ~326 warnings (nullable refs, unused vars, xUnit suggestions)
-- **Action**: Don't add new warnings; fix warnings in code you modify
-
-#### Issue: Test Timeouts
-- **Expected**: Tests can take 5-10 minutes
-- **Action**: Use appropriate timeout values (60-120 seconds for test commands)
-
-#### Issue: Restore Failures
-- **Solution**: Ensure `dotnet restore` completes before building
-- **Note**: Takes 15-20 seconds on first run
-
 #### Issue: NativeAot/SelfContained Build
+
 - **Solution**: Restore these projects explicitly:
   ```bash
   dotnet restore ./Examples/NativeAot/NativeAot.csproj -f
   dotnet restore ./Examples/SelfContained/SelfContained.csproj -f
   ```
 
-### Running Examples
-
-**UICatalog** (comprehensive demo app):
-```bash
-dotnet run --project Examples/UICatalog/UICatalog.csproj
-```
-
----
-
 ## Coding Conventions
 
+**⚠️ CRITICAL - These rules MUST be followed in ALL new or modified code**
+
 ### Code Style Tenets
 
 1. **Six-Year-Old Reading Level** - Readability over terseness
@@ -135,19 +118,18 @@ dotnet run --project Examples/UICatalog/UICatalog.csproj
 
 ### Code Formatting
 
+**⚠️ CRITICAL - These rules MUST be followed in ALL new or modified code:**
+
 - **Do NOT add formatting tools** - Use existing `.editorconfig` and `Terminal.sln.DotSettings`
 - Format code with:
   1. ReSharper/Rider (`Ctrl-E-C`)
   2. JetBrains CleanupCode CLI tool (free)
   3. Visual Studio (`Ctrl-K-D`) as fallback
 - **Only format files you modify**
-
-### Critical Coding Rules
-
-**⚠️ CRITICAL - These rules MUST be followed in ALL new or modified code:**
-
-#### Type Declarations and Object Creation
-
+- Follow `.editorconfig` settings (e.g., braces on new lines, spaces after keywords)
+- 4-space indentation
+- No trailing whitespace
+- File-scoped namespaces
 - **ALWAYS use explicit types** - Never use `var` except for built-in simple types (`int`, `string`, `bool`, `double`, `float`, `decimal`, `char`, `byte`)
   ```csharp
   // ✅ CORRECT - Explicit types
@@ -163,7 +145,7 @@ dotnet run --project Examples/UICatalog/UICatalog.csproj
   var views = new List<View?>();
   ```
 
-- **ALWAYS use target-typed `new()`** - Use `new ()` instead of `new TypeName()` when the type is already declared
+- **ALWAYS use target-typed `new ()`** - Use `new ()` instead of `new TypeName()` when the type is already declared
   ```csharp
   // ✅ CORRECT - Target-typed new
   View view = new () { Width = 10 };
@@ -174,40 +156,34 @@ dotnet run --project Examples/UICatalog/UICatalog.csproj
   MouseEventArgs args = new MouseEventArgs();
   ```
 
-#### Other Conventions
-
-- Follow `.editorconfig` settings (e.g., braces on new lines, spaces after keywords)
-- 4-space indentation
-- No trailing whitespace
-- File-scoped namespaces
-
 **⚠️ CRITICAL - These conventions apply to ALL code - production code, test code, examples, and samples.**
 
----
-
 ## Testing Requirements
 
 ### Code Coverage
 
 - **Never decrease code coverage** - PRs must maintain or increase coverage
 - Target: 70%+ coverage for new code
+- **Coverage collection**:
+- Centralized in `TestResults/` directory at repository root
+- Collected only on Linux (ubuntu-latest) runners in CI for performance
+- Windows and macOS runners skip coverage collection to reduce execution time
+- Coverage reports uploaded to Codecov automatically from Linux runner
 - CI monitors coverage on each PR
 
 ### Test Patterns
 
-- **Parallelizable tests preferred** - Add new tests to `UnitTestsParallelizable` when possible
-- **Avoid static dependencies** - Don't use `Application.Init`, `ConfigurationManager` in tests
-- **Don't use `[AutoInitShutdown]`** - Legacy pattern, being phased out
 - **Make tests granular** - Each test should cover smallest area possible
 - Follow existing test patterns in respective test projects
+- **Avoid adding new tests to the `UnitTests` Project** - Make them parallelizable and add them to `UnitTests.Parallelizable`
+- **Avoid static dependencies** - DO NOT use the legacy/static `Application` API or `ConfigurationManager` in tests unless the tests explicitly test related functionality.
+- **Don't use `[AutoInitShutdown]` or `[SetupFakeApplication]`** - Legacy pattern, being phased out
 
 ### Test Configuration
 
 - `xunit.runner.json` - xUnit configuration
 - `coverlet.runsettings` - Coverage settings (OpenCover format)
 
----
-
 ## API Documentation Requirements
 
 **All public APIs MUST have XML documentation:**
@@ -219,16 +195,15 @@ dotnet run --project Examples/UICatalog/UICatalog.csproj
 - Complex topics → `docfx/docs/*.md` files
 - Proper English and grammar - Clear, concise, complete. Use imperative mood.
 
----
-
 ## Pull Request Guidelines
 
 ### PR Requirements
 
+- **ALWAYS** include instructions for pulling down locally at end of Description
+
 - **Title**: "Fixes #issue. Terse description". If multiple issues, list all, separated by commas (e.g. "Fixes #123, #456. Terse description")
 - **Description**: 
   - Include "- Fixes #issue" for each issue near the top
-  - **ALWAYS** include instructions for pulling down locally at end of Description
   - Suggest user setup a remote named `copilot` pointing to your fork
   - Example:
     ```markdown
@@ -237,73 +212,14 @@ dotnet run --project Examples/UICatalog/UICatalog.csproj
     git fetch copilot <branch-name>
     git checkout copilot/<branch-name>
     ```
-- **Coding Style**: Follow all coding conventions in this document for new and modified code
 - **Tests**: Add tests for new functionality (see [Testing Requirements](#testing-requirements))
 - **Coverage**: Maintain or increase code coverage
 - **Scenarios**: Update UICatalog scenarios when adding features
 - **Warnings**: **CRITICAL - PRs must not introduce any new warnings**
   - Any file modified in a PR that currently generates warnings **MUST** be fixed to remove those warnings
   - Exception: Warnings caused by `[Obsolete]` attributes can remain
-  - Expected baseline: ~326 warnings (mostly nullable reference warnings, unused variables, xUnit suggestions)
   - Action: Before submitting a PR, verify your changes don't add new warnings and fix any warnings in files you modify
 
----
-
-## CI/CD Workflows
-
-The repository uses multiple GitHub Actions workflows. What runs and when:
-
-### 1) Build Solution (`.github/workflows/build.yml`)
-
-- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`); supports `workflow_call`
-- **Runner/timeout**: `ubuntu-latest`, 10 minutes
-- **Steps**:
-  - Checkout and setup .NET 8.x GA
-  - `dotnet restore`
-  - Build Debug: `dotnet build --configuration Debug --no-restore -property:NoWarn=0618%3B0612`
-  - Build Release (library): `dotnet build Terminal.Gui/Terminal.Gui.csproj --configuration Release --no-incremental --force -property:NoWarn=0618%3B0612`
-  - Pack Release: `dotnet pack Terminal.Gui/Terminal.Gui.csproj --configuration Release --output ./local_packages -property:NoWarn=0618%3B0612`
-  - Restore NativeAot/SelfContained examples, then restore solution again
-  - Build Release for `Examples/NativeAot` and `Examples/SelfContained`
-  - Build Release solution
-  - Upload artifacts named `build-artifacts`, retention 1 day
-
-### 2) Build & Run Unit Tests (`.github/workflows/unit-tests.yml`)
-
-- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
-- **Process**: Calls build workflow, then runs:
-  - Non-parallel UnitTests on Ubuntu/Windows/macOS matrix with coverage and blame/diag flags; `xunit.stopOnFail=false`
-  - Parallel UnitTestsParallelizable similarly with coverage; `xunit.stopOnFail=false`
-  - Uploads logs per-OS
-
-### 3) Build & Run Integration Tests (`.github/workflows/integration-tests.yml`)
-
-- **Triggers**: push and pull_request to `v2_release`, `v2_develop` (ignores `**.md`)
-- **Process**: Calls build workflow, then runs IntegrationTests on matrix with blame/diag; `xunit.stopOnFail=true`
-- Uploads logs per-OS
-
-### 4) Publish to NuGet (`.github/workflows/publish.yml`)
-
-- **Triggers**: push to `v2_release`, `v2_develop`, and tags `v*` (ignores `**.md`)
-- Uses GitVersion to compute SemVer, builds Release, packs with symbols, and pushes to NuGet.org using `NUGET_API_KEY`
-
-### 5) Build and publish API docs (`.github/workflows/api-docs.yml`)
-
-- **Triggers**: push to `v1_release` and `v2_develop`
-- Builds DocFX site on Windows and deploys to GitHub Pages when `ref_name` is `v2_release` or `v2_develop`
-
-### Replicating CI Locally
-
-```bash
-# Full CI sequence:
-dotnet restore
-dotnet build --configuration Debug --no-restore
-dotnet test Tests/UnitTests --no-build --verbosity normal
-dotnet test Tests/UnitTestsParallelizable --no-build --verbosity normal
-dotnet build --configuration Release --no-restore
-```
-
----
 
 ## Repository Structure
 
@@ -323,9 +239,9 @@ dotnet build --configuration Release --no-restore
 ### Main Directories
 
 **`/Terminal.Gui/`** - Core library (496 C# files):
-- `App/` - Application lifecycle (`Application.cs` static class, `RunState`, `MainLoop`)
+- `App/` - Application lifecycle (`Application.cs` static class, `SessionToken`, `MainLoop`)
 - `Configuration/` - `ConfigurationManager` for settings
-- `Drivers/` - Console driver implementations (`IConsoleDriver`, `NetDriver`, `UnixDriver`, `WindowsDriver`)
+- `Drivers/` - Console driver implementations (`Dotnet`, `Windows`, `Unix`, `Fake`)
 - `Drawing/` - Rendering system (attributes, colors, glyphs)
 - `Input/` - Keyboard and mouse input handling
 - `ViewBase/` - Core `View` class hierarchy and layout
@@ -355,7 +271,6 @@ dotnet build --configuration Release --no-restore
 
 **`/.github/workflows/`** - CI/CD pipelines (see [CI/CD Workflows](#cicd-workflows))
 
----
 
 ## Branching Model
 
@@ -365,31 +280,6 @@ dotnet build --configuration Release --no-restore
 - `v2_release` - Stable releases, matches NuGet
 - `v1_develop`, `v1_release` - Legacy v1 (maintenance only)
 
----
-
-## Key Architecture Concepts
-
-**⚠️ CRITICAL - Contributors should understand these concepts before starting work.**
-
-See `/docfx/docs/` for deep dives on:
-
-- **Application Lifecycle** - How `Application.Init`, `Application.Run`, and `Application.Shutdown` work
-- **View Hierarchy** - Understanding `View`, `Toplevel`, `Window`, and view containment
-- **Layout System** - Pos, Dim, and automatic layout
-- **Event System** - How keyboard, mouse, and application events flow
-- **Driver Architecture** - How console drivers abstract platform differences
-- **Drawing Model** - How rendering works with Attributes, Colors, and Glyphs
-
-Key documentation:
-- [View Documentation](https://gui-cs.github.io/Terminal.Gui/docs/View.html)
-- [Events Deep Dive](https://gui-cs.github.io/Terminal.Gui/docs/events.html)
-- [Layout System](https://gui-cs.github.io/Terminal.Gui/docs/layout.html)
-- [Keyboard Handling](https://gui-cs.github.io/Terminal.Gui/docs/keyboard.html)
-- [Mouse Support](https://gui-cs.github.io/Terminal.Gui/docs/mouse.html)
-- [Drivers](https://gui-cs.github.io/Terminal.Gui/docs/drivers.html)
-
----
-
 ## What NOT to Do
 
 - ❌ Don't add new linters/formatters (use existing)
@@ -403,17 +293,4 @@ Key documentation:
 - ❌ **Don't use redundant type names with `new`** (**ALWAYS PREFER** target-typed `new ()`)
 - ❌ **Don't introduce new warnings** (fix warnings in files you modify; exception: `[Obsolete]` warnings)
 
----
-
-## Additional Resources
-
-- **Full Documentation**: https://gui-cs.github.io/Terminal.Gui
-- **API Reference**: https://gui-cs.github.io/Terminal.Gui/api/Terminal.Gui.App.html
-- **Deep Dives**: `/docfx/docs/` directory
-- **Getting Started**: https://gui-cs.github.io/Terminal.Gui/docs/getting-started.html
-- **Migrating from v1 to v2**: https://gui-cs.github.io/Terminal.Gui/docs/migratingfromv1.html
-- **Showcase**: https://gui-cs.github.io/Terminal.Gui/docs/showcase.html
-
----
-
 **Thank you for contributing to Terminal.Gui!** 🎉

+ 1 - 1
Directory.Packages.props

@@ -18,7 +18,7 @@
     <PackageVersion Include="Microsoft.Extensions.Logging.Abstractions" Version="[9.0.0,10)" />
     <PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.6" />
     <PackageVersion Include="System.IO.Abstractions" Version="[22.0.16,23)" />
-    <PackageVersion Include="Wcwidth" Version="[3.0.0,)" />
+    <PackageVersion Include="Wcwidth" Version="[4.0.0,)" />
     <PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="[1.21.2,2)" />
     <PackageVersion Include="Serilog" Version="4.2.0" />
     <PackageVersion Include="Serilog.Extensions.Logging" Version="9.0.0" />

+ 0 - 2
Examples/CommunityToolkitExample/LoginView.cs

@@ -64,8 +64,6 @@ internal partial class LoginView : IRecipient<Message<LoginActions>>
                 }
         }
         SetText ();
-        // BUGBUG: This should not be needed:
-        Application.LayoutAndDraw ();
     }
 
     private void SetText ()

+ 4 - 4
Examples/CommunityToolkitExample/LoginViewModel.cs

@@ -12,7 +12,7 @@ internal partial class LoginViewModel : ObservableObject
     private const string INVALID_LOGIN_MESSAGE = "Please enter a valid user name and password.";
     private const string LOGGING_IN_PROGRESS_MESSAGE = "Logging in...";
     private const string VALID_LOGIN_MESSAGE = "The input is valid!";
-    
+
     [ObservableProperty]
     private bool _canLogin;
 
@@ -28,7 +28,7 @@ internal partial class LoginViewModel : ObservableObject
 
     [ObservableProperty]
     private string _usernameLengthMessage;
-    
+
     [ObservableProperty]
     private Scheme? _validationScheme;
 
@@ -105,7 +105,7 @@ internal partial class LoginViewModel : ObservableObject
     {
         switch (loginAction)
         {
-             case LoginActions.Clear:
+            case LoginActions.Clear:
                 LoginProgressMessage = message;
                 ValidationMessage = INVALID_LOGIN_MESSAGE;
                 ValidationScheme = SchemeManager.GetScheme ("Error");
@@ -115,7 +115,7 @@ internal partial class LoginViewModel : ObservableObject
                 break;
             case LoginActions.Validation:
                 ValidationMessage = CanLogin ? VALID_LOGIN_MESSAGE : INVALID_LOGIN_MESSAGE;
-                ValidationScheme = CanLogin ? SchemeManager.GetScheme ("Base") : SchemeManager.GetScheme("Error");
+                ValidationScheme = CanLogin ? SchemeManager.GetScheme ("Base") : SchemeManager.GetScheme ("Error");
                 break;
         }
         WeakReferenceMessenger.Default.Send (new Message<LoginActions> { Value = loginAction });

+ 0 - 1
Examples/CommunityToolkitExample/Message.cs

@@ -1,5 +1,4 @@
 namespace CommunityToolkitExample;
-
 internal class Message<T>
 {
     public T? Value { get; set; }

+ 7 - 8
Examples/CommunityToolkitExample/Program.cs

@@ -1,8 +1,6 @@
 using Microsoft.Extensions.DependencyInjection;
-using Terminal.Gui.Configuration;
 using Terminal.Gui.App;
-using Terminal.Gui.ViewBase;
-
+using Terminal.Gui.Configuration;
 
 namespace CommunityToolkitExample;
 
@@ -14,10 +12,10 @@ public static class Program
     {
         ConfigurationManager.Enable (ConfigLocations.All);
         Services = ConfigureServices ();
-        Application.Init ();
-        Application.Run (Services.GetRequiredService<LoginView> ());
-        Application.Top?.Dispose ();
-        Application.Shutdown ();
+        using IApplication app = Application.Create ();
+        app.Init ();
+        using var loginView = Services.GetRequiredService<LoginView> ();
+        app.Run (loginView);
     }
 
     private static IServiceProvider ConfigureServices ()
@@ -25,6 +23,7 @@ public static class Program
         var services = new ServiceCollection ();
         services.AddTransient<LoginView> ();
         services.AddTransient<LoginViewModel> ();
+
         return services.BuildServiceProvider ();
     }
-}
+}

+ 25 - 21
Examples/CommunityToolkitExample/README.md

@@ -6,9 +6,10 @@ Right away we use IoC to load our views and view models.
 
 ``` csharp
 // As a public property for access further in the application if needed. 
-public static IServiceProvider Services { get; private set; }
+public static IServiceProvider? Services { get; private set; }
 ...
 // In Main
+ConfigurationManager.Enable (ConfigLocations.All);
 Services = ConfigureServices ();
 ...
 private static IServiceProvider ConfigureServices ()
@@ -20,16 +21,19 @@ private static IServiceProvider ConfigureServices ()
 }
 ```
 
-Now, we start the app and get our main view.
+Now, we start the app using the modern Terminal.Gui model and get our main view.
 
 ``` csharp
-Application.Run (Services.GetRequiredService<LoginView> ());
+using IApplication app = Application.Create ();
+app.Init ();
+using var loginView = Services.GetRequiredService<LoginView> ();
+app.Run (loginView);
 ```
 
 Our view implements `IRecipient<T>` to demonstrate the use of the `WeakReferenceMessenger`. The binding of the view events is then created.
 
 ``` csharp
-internal partial class LoginView : IRecipient<Message<LoginAction>>
+internal partial class LoginView : IRecipient<Message<LoginActions>>
 {
     public LoginView (LoginViewModel viewModel)
     {
@@ -41,15 +45,16 @@ internal partial class LoginView : IRecipient<Message<LoginAction>>
         passwordInput.TextChanged += (_, _) =>
                                      {
                                          ViewModel.Password = passwordInput.Text;
-                                         SetText ();
                                      };
-        loginButton.Accept += (_, _) =>
+        loginButton.Accepting += (_, e) =>
                               {
                                   if (!ViewModel.CanLogin) { return; }
                                   ViewModel.LoginCommand.Execute (null);
+                                  // When Accepting is handled, set e.Handled to true to prevent further processing.
+                                  e.Handled = true;
                               };
         ...
-        // Let the view model know the view is intialized.
+        // Let the view model know the view is initialized.
         Initialized += (_, _) => { ViewModel.Initialized (); };
     }
     ...
@@ -101,54 +106,53 @@ The use of `WeakReferenceMessenger` provides one method of signaling the view fr
 ...
 private async Task Login ()
 {
-    SendMessage (LoginAction.LoginProgress, LOGGING_IN_PROGRESS_MESSAGE);
+    SendMessage (LoginActions.LoginProgress, LOGGING_IN_PROGRESS_MESSAGE);
     await Task.Delay (TimeSpan.FromSeconds (1));
     Clear ();
 }
 
-private void SendMessage (LoginAction loginAction, string message = "")
+private void SendMessage (LoginActions loginAction, string message = "")
 {
     switch (loginAction)
     {
-        case LoginAction.LoginProgress:
+        case LoginActions.LoginProgress:
             LoginProgressMessage = message;
             break;
-        case LoginAction.Validation:
+        case LoginActions.Validation:
             ValidationMessage = CanLogin ? VALID_LOGIN_MESSAGE : INVALID_LOGIN_MESSAGE;
-            ValidationScheme = CanLogin ? Colors.Schemes ["Base"] : Colors.Schemes ["Error"];
+            ValidationScheme = CanLogin ? SchemeManager.GetScheme ("Base") : SchemeManager.GetScheme ("Error");
             break;
     }
-    WeakReferenceMessenger.Default.Send (new Message<LoginAction> { Value = loginAction });
+    WeakReferenceMessenger.Default.Send (new Message<LoginActions> { Value = loginAction });
 }
 
 private void ValidateLogin ()
 {
     CanLogin = !string.IsNullOrEmpty (Username) && !string.IsNullOrEmpty (Password);
-    SendMessage (LoginAction.Validation);
+    SendMessage (LoginActions.Validation);
 }
 ...
 ```
 
-And the view's `Receive` function which provides an `Application.Refresh()` call to update the UI immediately.
+The view's `Receive` function updates the UI based on messages from the view model. In the modern Terminal.Gui model, UI updates are automatically refreshed, so no manual `Application.Refresh()` call is needed.
 
 ``` csharp
-public void Receive (Message<LoginAction> message)
+public void Receive (Message<LoginActions> message)
 {
     switch (message.Value)
     {
-        case LoginAction.LoginProgress:
+        case LoginActions.LoginProgress:
             {
                 loginProgressLabel.Text = ViewModel.LoginProgressMessage;
                 break;
             }
-        case LoginAction.Validation:
+        case LoginActions.Validation:
             {
                 validationLabel.Text = ViewModel.ValidationMessage;
-                validationLabel.Scheme = ViewModel.ValidationScheme;
+                validationLabel.SetScheme (ViewModel.ValidationScheme);
                 break;
             }
     }
-    SetText();
-    Application.Refresh ();
+    SetText ();
 }
 ```

+ 27 - 36
Examples/Example/Example.cs

@@ -3,30 +3,28 @@
 // This is a simple example application.  For the full range of functionality
 // see the UICatalog project
 
-using Terminal.Gui.Configuration;
 using Terminal.Gui.App;
-using Terminal.Gui.Drawing;
+using Terminal.Gui.Configuration;
 using Terminal.Gui.ViewBase;
 using Terminal.Gui.Views;
-using Attribute = Terminal.Gui.Drawing.Attribute;
 
 // Override the default configuration for the application to use the Light theme
-//ConfigurationManager.RuntimeConfig = """{ "Theme": "Light" }""";
-ConfigurationManager.Enable(ConfigLocations.All);
-
+ConfigurationManager.RuntimeConfig = """{ "Theme": "Light" }""";
+ConfigurationManager.Enable (ConfigLocations.All);
 
+IApplication app = Application.Create ();
 
-Application.Run<ExampleWindow> ().Dispose ();
+app.Run<ExampleWindow> ();
 
-// Before the application exits, reset Terminal.Gui for clean shutdown
-Application.Shutdown ();
+// Dispose the app to clean up and enable Console.WriteLine below
+app.Dispose ();
 
 // To see this output on the screen it must be done after shutdown,
 // which restores the previous screen.
 Console.WriteLine ($@"Username: {ExampleWindow.UserName}");
 
 // Defines a top-level window with border and title
-public class ExampleWindow : Window
+public sealed class ExampleWindow : Window
 {
     public static string UserName { get; set; }
 
@@ -74,39 +72,32 @@ public class ExampleWindow : Window
 
         // When login button is clicked display a message popup
         btnLogin.Accepting += (s, e) =>
-                           {
-                               if (userNameText.Text == "admin" && passwordText.Text == "password")
-                               {
-                                   MessageBox.Query ("Logging In", "Login Successful", "Ok");
-                                   UserName = userNameText.Text;
-                                   Application.RequestStop ();
-                               }
-                               else
-                               {
-                                   MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok");
-                               }
-                               // When Accepting is handled, set e.Handled to true to prevent further processing.
-                               e.Handled = true;
-                           };
+                              {
+                                  if (userNameText.Text == "admin" && passwordText.Text == "password")
+                                  {
+                                      MessageBox.Query (App, "Logging In", "Login Successful", "Ok");
+                                      UserName = userNameText.Text;
+                                      Application.RequestStop ();
+                                  }
+                                  else
+                                  {
+                                      MessageBox.ErrorQuery (App, "Logging In", "Incorrect username or password", "Ok");
+                                  }
+
+                                  // When Accepting is handled, set e.Handled to true to prevent further processing.
+                                  e.Handled = true;
+                              };
 
         // Add the views to the Window
         Add (usernameLabel, userNameText, passwordLabel, passwordText, btnLogin);
 
-        ListView lv = new ListView ()
+        var lv = new ListView
         {
-            Y = Pos.AnchorEnd(),
-            Height= Dim.Auto(),
-            Width = Dim.Auto()
+            Y = Pos.AnchorEnd (),
+            Height = Dim.Auto (),
+            Width = Dim.Auto ()
         };
         lv.SetSource (["One", "Two", "Three", "Four"]);
         Add (lv);
     }
-
-    public override void EndInit ()
-    {
-        base.EndInit ();
-        // Set the theme to "Anders" if it exists, otherwise use "Default"
-        ThemeManager.Theme = ThemeManager.GetThemeNames ().FirstOrDefault (x => x == "Anders") ?? "Default";
-    }
 }
- 

+ 1 - 4
Examples/Example/README.md

@@ -1,11 +1,8 @@
 # Terminal.Gui C# Example
 
-This example shows how to use the Terminal.Gui library to create a simple GUI application in C#.
+This example shows how to use the Terminal.Gui library to create a simple TUI application in C#.
 
 This is the same code found in the Terminal.Gui README.md file.
 
 To explore the full range of functionality in Terminal.Gui, see the [UICatalog](../UICatalog) project
 
-See [README.md](https://github.com/gui-cs/Terminal.Gui) for a list of all Terminal.Gui samples.
-
-Note, the old `demo.cs` example has been deleted because it was not a very good example. It can still be found in the [git history](https://github.com/gui-cs/Terminal.Gui/tree/v1.8.2).

+ 11 - 0
Examples/FluentExample/FluentExample.csproj

@@ -0,0 +1,11 @@
+<Project Sdk="Microsoft.NET.Sdk">
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0</TargetFramework>
+    <LangVersion>preview</LangVersion>
+    <Nullable>enable</Nullable>
+  </PropertyGroup>
+  <ItemGroup>
+    <ProjectReference Include="..\..\Terminal.Gui\Terminal.Gui.csproj" />
+  </ItemGroup>
+</Project>

+ 109 - 0
Examples/FluentExample/Program.cs

@@ -0,0 +1,109 @@
+// Fluent API example demonstrating IRunnable with automatic disposal and result extraction
+
+using Terminal.Gui.App;
+using Terminal.Gui.Drawing;
+using Terminal.Gui.ViewBase;
+using Terminal.Gui.Views;
+
+IApplication? app = Application.Create ()
+                               .Init ()
+                               .Run<ColorPickerView> ();
+
+// Run the application with fluent API - automatically creates, runs, and disposes the runnable
+Color? result = app.GetResult () as Color?;
+
+// Shut down the app with Dispose before we can use Console.WriteLine
+app.Dispose ();
+
+if (result is { })
+{
+    Console.WriteLine (@$"Selected Color: {result}");
+}
+else
+{
+    Console.WriteLine (@"No color selected");
+}
+
+/// <summary>
+///     A runnable view that allows the user to select a color.
+///     Demonstrates the Runnable with type pattern with automatic disposal.
+/// </summary>
+public class ColorPickerView : Runnable<Color?>
+{
+    public ColorPickerView ()
+    {
+        Title = "Select a Color (Esc to quit)";
+        BorderStyle = LineStyle.Single;
+        Height = Dim.Auto ();
+        Width = Dim.Auto ();
+
+        // Add instructions
+        var instructions = new Label
+        {
+            Text = "Use arrow keys to select a color, Enter to accept",
+            X = Pos.Center (),
+            Y = 0
+        };
+
+        // Create color picker
+        ColorPicker colorPicker = new ()
+        {
+            X = Pos.Center (),
+            Y = Pos.Bottom (instructions),
+            Style = new ColorPickerStyle ()
+            {
+                ShowColorName = true,
+                ShowTextFields = true
+            }
+        };
+        colorPicker.ApplyStyleChanges ();
+
+        // Create OK button
+        Button okButton = new ()
+        {
+            Title = "_OK",
+            X = Pos.Align (Alignment.Center),
+            Y = Pos.AnchorEnd (),
+            IsDefault = true
+        };
+
+        okButton.Accepting += (s, e) =>
+                              {
+                                  // Extract result before stopping
+                                  Result = colorPicker.SelectedColor;
+                                  RequestStop ();
+                                  e.Handled = true;
+                              };
+
+        // Create Cancel button
+        Button cancelButton = new ()
+        {
+            Title = "_Cancel",
+            X = Pos.Align (Alignment.Center),
+            Y = Pos.AnchorEnd ()
+        };
+
+        cancelButton.Accepting += (s, e) =>
+                                  {
+                                      // Don't set result - leave as null
+                                      RequestStop ();
+                                      e.Handled = true;
+                                  };
+
+        // Add views
+        Add (instructions, colorPicker, okButton, cancelButton);
+    }
+
+    protected override bool OnIsRunningChanging (bool oldIsRunning, bool newIsRunning)
+    {
+        // Alternative place to extract result before stopping
+        // This is called before the view is removed from the stack
+        if (!newIsRunning && Result is null)
+        {
+            // User pressed Esc - could extract current selection here
+            //Result = SelectedColor;
+        }
+
+        return base.OnIsRunningChanging (oldIsRunning, newIsRunning);
+    }
+}

+ 4 - 4
Examples/NativeAot/Program.cs

@@ -12,8 +12,8 @@ namespace NativeAot;
 
 public static class Program
 {
-    [RequiresUnreferencedCode ("Calls Terminal.Gui.Application.Init(IConsoleDriver, String)")]
-    [RequiresDynamicCode ("Calls Terminal.Gui.Application.Init(IConsoleDriver, String)")]
+    [RequiresUnreferencedCode ("Calls Terminal.Gui.Application.Init(IDriver, String)")]
+    [RequiresDynamicCode ("Calls Terminal.Gui.Application.Init(IDriver, String)")]
     private static void Main (string [] args)
     {
         ConfigurationManager.Enable(ConfigLocations.All);
@@ -101,13 +101,13 @@ public class ExampleWindow : Window
         {
             if (userNameText.Text == "admin" && passwordText.Text == "password")
             {
-                MessageBox.Query ("Logging In", "Login Successful", "Ok");
+                MessageBox.Query (App, "Logging In", "Login Successful", "Ok");
                 UserName = userNameText.Text;
                 Application.RequestStop ();
             }
             else
             {
-                MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok");
+                MessageBox.ErrorQuery (App, "Logging In", "Incorrect username or password", "Ok");
             }
             // Anytime Accepting is handled, make sure to set e.Handled to true.
             e.Handled = true;

+ 7 - 8
Examples/ReactiveExample/Program.cs

@@ -1,9 +1,7 @@
 using System.Reactive.Concurrency;
 using ReactiveUI;
-using ReactiveUI.SourceGenerators;
-using Terminal.Gui.Configuration;
 using Terminal.Gui.App;
-using Terminal.Gui.ViewBase;
+using Terminal.Gui.Configuration;
 
 namespace ReactiveExample;
 
@@ -12,11 +10,12 @@ public static class Program
     private static void Main (string [] args)
     {
         ConfigurationManager.Enable (ConfigLocations.All);
-        Application.Init ();
-        RxApp.MainThreadScheduler = TerminalScheduler.Default;
+        using IApplication app = Application.Create ();
+        app.Init ();
+        RxApp.MainThreadScheduler = new TerminalScheduler (app);
         RxApp.TaskpoolScheduler = TaskPoolScheduler.Default;
-        Application.Run (new LoginView (new LoginViewModel ()));
-        Application.Top.Dispose ();
-        Application.Shutdown ();
+        var loginView = new LoginView (new ());
+        app.Run (loginView);
+        loginView.Dispose ();
     }
 }

+ 8 - 4
Examples/ReactiveExample/README.md

@@ -7,10 +7,14 @@ This is a sample app that shows how to use `System.Reactive` and `ReactiveUI` wi
 In order to use reactive extensions scheduling, copy-paste the `TerminalScheduler.cs` file into your project, and add the following lines to the composition root of your `Terminal.Gui` application:
 
 ```cs
-Application.Init ();
-RxApp.MainThreadScheduler = TerminalScheduler.Default;
+ConfigurationManager.Enable (ConfigLocations.All);
+using IApplication app = Application.Create ();
+app.Init ();
+RxApp.MainThreadScheduler = new TerminalScheduler (app);
 RxApp.TaskpoolScheduler = TaskPoolScheduler.Default;
-Application.Run (new RootView (new RootViewModel ()));
+var loginView = new LoginView (new ());
+app.Run (loginView);
+loginView.Dispose ();
 ```
 
 From now on, you can use `.ObserveOn(RxApp.MainThreadScheduler)` to return to the main loop from a background thread. This is useful when you have a `IObservable<TValue>` updated from a background thread, and you wish to update the UI with `TValue`s received from that observable.
@@ -43,6 +47,6 @@ If you combine `OneWay` and `OneWayToSource` data bindings, you get `TwoWay` dat
 // 'clearButton' is 'Button'
 clearButton
 	.Events ()
-	.Clicked
+	.Accepting
 	.InvokeCommand (ViewModel, x => x.Clear);
 ```

+ 28 - 21
Examples/ReactiveExample/TerminalScheduler.cs

@@ -1,4 +1,4 @@
-using System;
+#nullable enable
 using System.Reactive.Concurrency;
 using System.Reactive.Disposables;
 using Terminal.Gui.App;
@@ -7,8 +7,9 @@ namespace ReactiveExample;
 
 public class TerminalScheduler : LocalScheduler
 {
-    public static readonly TerminalScheduler Default = new ();
-    private TerminalScheduler () { }
+    public TerminalScheduler (IApplication? application) { _application = application; }
+
+    private readonly IApplication? _application = null;
 
     public override IDisposable Schedule<TState> (
         TState state,
@@ -21,15 +22,15 @@ public class TerminalScheduler : LocalScheduler
             var composite = new CompositeDisposable (2);
             var cancellation = new CancellationDisposable ();
 
-            Application.Invoke (
-                                () =>
-                                {
-                                    if (!cancellation.Token.IsCancellationRequested)
-                                    {
-                                        composite.Add (action (this, state));
-                                    }
-                                }
-                               );
+            _application?.Invoke (
+                                 (_) =>
+                                 {
+                                     if (!cancellation.Token.IsCancellationRequested)
+                                     {
+                                         composite.Add (action (this, state));
+                                     }
+                                 }
+                                );
             composite.Add (cancellation);
 
             return composite;
@@ -39,16 +40,22 @@ public class TerminalScheduler : LocalScheduler
         {
             var composite = new CompositeDisposable (2);
 
-            object timeout = Application.AddTimeout (
-                                                     dueTime,
-                                                     () =>
-                                                     {
-                                                         composite.Add (action (this, state));
+            object? timeout = _application?.AddTimeout (
+                                                      dueTime,
+                                                      () =>
+                                                      {
+                                                          composite.Add (action (this, state));
 
-                                                         return false;
-                                                     }
-                                                    );
-            composite.Add (Disposable.Create (() => Application.RemoveTimeout (timeout)));
+                                                          return false;
+                                                      }
+                                                     );
+            composite.Add (Disposable.Create (() =>
+                                              {
+                                                  if (timeout is { })
+                                                  {
+                                                      _application?.RemoveTimeout (timeout);
+                                                  }
+                                              }));
 
             return composite;
         }

+ 1 - 2
Examples/ReactiveExample/ViewExtensions.cs

@@ -1,5 +1,4 @@
-using System;
-using Terminal.Gui.ViewBase;
+using Terminal.Gui.ViewBase;
 using Terminal.Gui.Views;
 
 namespace ReactiveExample;

+ 168 - 0
Examples/RunnableWrapperExample/Program.cs

@@ -0,0 +1,168 @@
+// Example demonstrating how to make ANY View runnable without implementing IRunnable
+
+using Terminal.Gui.App;
+using Terminal.Gui.Drawing;
+using Terminal.Gui.ViewBase;
+using Terminal.Gui.Views;
+
+IApplication app = Application.Create ();
+app.Init ();
+
+// Example 1: Use extension method with result extraction
+var textField = new TextField { Width = 40, Text = "Default text" };
+textField.Title = "Enter your name";
+textField.BorderStyle = LineStyle.Single;
+
+RunnableWrapper<TextField, string> textRunnable = textField.AsRunnable (tf => tf.Text);
+app.Run (textRunnable);
+
+if (textRunnable.Result is { } name)
+{
+    MessageBox.Query (app, "Result", $"You entered: {name}", "OK");
+}
+else
+{
+    MessageBox.Query (app, "Result", "Canceled", "OK");
+}
+
+textRunnable.Dispose ();
+
+// Example 2: Use IApplication.RunView() for one-liner
+Color selectedColor = app.RunView (
+                                   new ColorPicker
+                                   {
+                                       Title = "Pick a Color",
+                                       BorderStyle = LineStyle.Single
+                                   },
+                                   cp => cp.SelectedColor);
+
+MessageBox.Query (app, "Result", $"Selected color: {selectedColor}", "OK");
+
+// Example 3: FlagSelector with typed enum result
+FlagSelector<SelectorStyles> flagSelector = new()
+{
+    Title = "Choose Styles",
+    BorderStyle = LineStyle.Single
+};
+
+RunnableWrapper<FlagSelector<SelectorStyles>, SelectorStyles?> flagsRunnable = flagSelector.AsRunnable (fs => fs.Value);
+app.Run (flagsRunnable);
+
+MessageBox.Query (app, "Result", $"Selected styles: {flagsRunnable.Result}", "OK");
+flagsRunnable.Dispose ();
+
+// Example 4: Any View without result extraction
+var label = new Label
+{
+    Text = "Press Esc to continue...",
+    X = Pos.Center (),
+    Y = Pos.Center ()
+};
+
+RunnableWrapper<Label, object> labelRunnable = label.AsRunnable ();
+app.Run (labelRunnable);
+
+// Can still access the wrapped view
+MessageBox.Query (app, "Result", $"Label text was: {labelRunnable.WrappedView.Text}", "OK");
+labelRunnable.Dispose ();
+
+// Example 5: Complex custom View made runnable
+View formView = CreateCustomForm ();
+RunnableWrapper<View, FormData> formRunnable = formView.AsRunnable (ExtractFormData);
+
+app.Run (formRunnable);
+
+if (formRunnable.Result is { } formData)
+{
+    MessageBox.Query (
+                      app,
+                      "Form Results",
+                      $"Name: {formData.Name}\nAge: {formData.Age}\nAgreed: {formData.Agreed}",
+                      "OK");
+}
+
+formRunnable.Dispose ();
+
+app.Dispose ();
+
+// Helper method to create a custom form
+View CreateCustomForm ()
+{
+    var form = new View
+    {
+        Title = "User Information",
+        BorderStyle = LineStyle.Single,
+        Width = 50,
+        Height = 10
+    };
+
+    var nameField = new TextField
+    {
+        Id = "nameField",
+        X = 10,
+        Y = 1,
+        Width = 30
+    };
+
+    var ageField = new TextField
+    {
+        Id = "ageField",
+        X = 10,
+        Y = 3,
+        Width = 10
+    };
+
+    var agreeCheckbox = new CheckBox
+    {
+        Id = "agreeCheckbox",
+        Title = "I agree to terms",
+        X = 10,
+        Y = 5
+    };
+
+    var okButton = new Button
+    {
+        Title = "OK",
+        X = Pos.Center (),
+        Y = 7,
+        IsDefault = true
+    };
+
+    okButton.Accepting += (s, e) =>
+                          {
+                              form.App?.RequestStop ();
+                              e.Handled = true;
+                          };
+
+    form.Add (new Label { Text = "Name:", X = 2, Y = 1 });
+    form.Add (nameField);
+    form.Add (new Label { Text = "Age:", X = 2, Y = 3 });
+    form.Add (ageField);
+    form.Add (agreeCheckbox);
+    form.Add (okButton);
+
+    return form;
+}
+
+// Helper method to extract data from the custom form
+FormData ExtractFormData (View form)
+{
+    var nameField = form.SubViews.FirstOrDefault (v => v.Id == "nameField") as TextField;
+    var ageField = form.SubViews.FirstOrDefault (v => v.Id == "ageField") as TextField;
+    var agreeCheckbox = form.SubViews.FirstOrDefault (v => v.Id == "agreeCheckbox") as CheckBox;
+
+    return new()
+    {
+        Name = nameField?.Text ?? string.Empty,
+        Age = int.TryParse (ageField?.Text, out int age) ? age : 0,
+        Agreed = agreeCheckbox?.CheckedState == CheckState.Checked
+    };
+}
+
+// Result type for custom form
+internal record FormData
+{
+    public string Name { get; init; } = string.Empty;
+    public int Age { get; init; }
+    public bool Agreed { get; init; }
+}

+ 15 - 0
Examples/RunnableWrapperExample/RunnableWrapperExample.csproj

@@ -0,0 +1,15 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+  <PropertyGroup>
+    <OutputType>Exe</OutputType>
+    <TargetFramework>net8.0</TargetFramework>
+    <ImplicitUsings>enable</ImplicitUsings>
+    <Nullable>enable</Nullable>
+    <LangVersion>latest</LangVersion>
+  </PropertyGroup>
+
+  <ItemGroup>
+    <ProjectReference Include="..\..\Terminal.Gui\Terminal.Gui.csproj" />
+  </ItemGroup>
+
+</Project>

+ 16 - 16
Examples/SelfContained/Program.cs

@@ -5,6 +5,7 @@ using System.Diagnostics.CodeAnalysis;
 using System.Globalization;
 using Terminal.Gui.Configuration;
 using Terminal.Gui.App;
+using Terminal.Gui.Drawing;
 using Terminal.Gui.ViewBase;
 using Terminal.Gui.Views;
 
@@ -12,11 +13,13 @@ namespace SelfContained;
 
 public static class Program
 {
-    [RequiresUnreferencedCode ("Calls Terminal.Gui.Application.Run<T>(Func<Exception, Boolean>, IConsoleDriver)")]
+    [RequiresUnreferencedCode ("Calls Terminal.Gui.Application.Run<T>(Func<Exception, Boolean>, IDriver)")]
     private static void Main (string [] args)
     {
         ConfigurationManager.Enable (ConfigLocations.All);
-        Application.Init ();
+
+        IApplication app = Application.Create ();
+        app.Init ();
 
         #region The code in this region is not intended for use in a self-contained single-file. It's just here to make sure there is no functionality break with localization in Terminal.Gui using single-file
 
@@ -33,28 +36,25 @@ public static class Program
 
         #endregion
 
-        ExampleWindow app = new ();
-        Application.Run (app);
+        using ExampleWindow exampleWindow = new ();
+        string? userName = app.Run (exampleWindow) as string;
 
-        // Dispose the app object before shutdown
-        app.Dispose ();
 
-        // Before the application exits, reset Terminal.Gui for clean shutdown
-        Application.Shutdown ();
+        // Shutdown the application in order to free resources and clean up the terminal
+        app.Dispose ();
 
         // To see this output on the screen it must be done after shutdown,
         // which restores the previous screen.
-        Console.WriteLine ($@"Username: {ExampleWindow.UserName}");
+        Console.WriteLine ($@"Username: {userName}");
     }
 }
 
 // Defines a top-level window with border and title
-public class ExampleWindow : Window
+public class ExampleWindow : Runnable<string>
 {
-    public static string? UserName;
-
     public ExampleWindow ()
     {
+        BorderStyle = LineStyle.Single;
         Title = $"Example App ({Application.QuitKey} to quit)";
 
         // Create input components and labels
@@ -100,13 +100,13 @@ public class ExampleWindow : Window
                            {
                                if (userNameText.Text == "admin" && passwordText.Text == "password")
                                {
-                                   MessageBox.Query ("Logging In", "Login Successful", "Ok");
-                                   UserName = userNameText.Text;
-                                   Application.RequestStop ();
+                                   MessageBox.Query (App, "Logging In", "Login Successful", "Ok");
+                                   Result = userNameText.Text;
+                                   App?.RequestStop ();
                                }
                                else
                                {
-                                   MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok");
+                                   MessageBox.ErrorQuery (App, "Logging In", "Incorrect username or password", "Ok");
                                }
                                // When Accepting is handled, set e.Handled to true to prevent further processing.
                                e.Handled = true;

+ 26 - 0
Examples/SelfContained/README.md

@@ -2,6 +2,32 @@
 
 This project aims to test the `Terminal.Gui` library to create a simple `self-contained` `single-file` GUI application in C#, ensuring that all its features are available.
 
+## Modern Terminal.Gui API
+
+This example uses the modern Terminal.Gui application model:
+
+```csharp
+ConfigurationManager.Enable (ConfigLocations.All);
+
+IApplication app = Application.Create ();
+app.Init ();
+
+using ExampleWindow exampleWindow = new ();
+string? userName = app.Run (exampleWindow) as string;
+
+app.Dispose ();
+
+Console.WriteLine ($@"Username: {userName}");
+```
+
+Key aspects of the modern model:
+- Use `Application.Create()` to create an `IApplication` instance
+- Call `app.Init()` to initialize the application
+- Use `app.Run(view)` to run views with proper resource management
+- Call `app.Dispose()` to clean up resources and restore the terminal
+- Event handling uses `Accepting` event instead of legacy `Accept` event
+- Set `e.Handled = true` in event handlers to prevent further processing
+
 With `Debug` the `.csproj` is used and with `Release` the latest `nuget package` is used, either in `Solution Configurations` or in `Profile Publish`.
 
 To publish the self-contained single file in `Debug` or `Release` mode, it is not necessary to select it in the `Solution Configurations`, just choose the `Debug` or `Release` configuration in the `Publish Profile`.

+ 1 - 1
Examples/UICatalog/README.md

@@ -80,7 +80,7 @@ The default `Window` shows the Scenario name and supports exiting the Scenario t
 
 ![screenshot](generic_screenshot.png)
 
-To build a more advanced scenario, where control of the `Toplevel` and `Window` is needed (e.g. for scenarios using `MenuBar` or `StatusBar`), simply use `Application.Top` per normal Terminal.Gui programming, as seen in the `Notepad` scenario.
+To build a more advanced scenario, where control of the `Runnable` and `Window` is needed (e.g. for scenarios using `MenuBar` or `StatusBar`), simply use `Application.Top` per normal Terminal.Gui programming, as seen in the `Notepad` scenario.
 
 For complete control, the `Init` and `Run` overrides can be implemented. The `base.Init` creates `Win`. The `base.Run` simply calls `Application.Run(Application.Top)`.
 

+ 6 - 7
Examples/UICatalog/Resources/config.json

@@ -11,7 +11,7 @@
       "Hot Dog Stand": {
         "Schemes": [
           {
-            "Toplevel": {
+            "Runnable": {
               "Normal": {
                 "Foreground": "Black",
                 "Background": "#FFFF00"
@@ -86,7 +86,7 @@
             "Menu": {
               "Normal": {
                 "Foreground": "Black",
-                "Background": "WHite"
+                "Background": "White"
               },
               "Focus": {
                 "Foreground": "White",
@@ -136,22 +136,21 @@
     {
       "UI Catalog Theme": {
         "Window.DefaultShadow": "Transparent",
+        "Button.DefaultShadow": "None",
         "CheckBox.DefaultHighlightStates": "In, Pressed, PressedOutside",
         "MessageBox.DefaultButtonAlignment": "Start",
         "StatusBar.DefaultSeparatorLineStyle": "Single",
         "Dialog.DefaultMinimumWidth": 80,
-        "MessageBox.DefaultBorderStyle": "Dotted",
         "NerdFonts.Enable": false,
         "MessageBox.DefaultMinimumWidth": 0,
         "Window.DefaultBorderStyle": "Double",
         "Dialog.DefaultShadow": "Opaque",
         "Dialog.DefaultButtonAlignment": "Start",
-        "Button.DefaultShadow": "Transparent",
         "FrameView.DefaultBorderStyle": "Double",
         "MessageBox.DefaultMinimumHeight": 0,
         "Button.DefaultHighlightStates": "In, Pressed",
-        "Menuv2.DefaultBorderStyle": "Heavy",
-        "MenuBarv2.DefaultBorderStyle": "Heavy",
+        "Menu.DefaultBorderStyle": "Heavy",
+        "MenuBar.DefaultBorderStyle": "Heavy",
         "Schemes": [
           {
             "UI Catalog Scheme": {
@@ -178,7 +177,7 @@
             }
           },
           {
-            "TopLevel": {
+            "Runnable": {
               "Normal": {
                 "Foreground": "DarkGray",
                 "Background": "White"

+ 16 - 21
Examples/UICatalog/Scenario.cs

@@ -67,7 +67,7 @@ namespace UICatalog;
 ///         };
 /// 
 ///         var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
-///         button.Accept += (s, e) => MessageBox.ErrorQuery ("Error", "You pressed the button!", "Ok");
+///         button.Accept += (s, e) => MessageBox.ErrorQuery (App, "Error", "You pressed the button!", "Ok");
 ///         appWindow.Add (button);
 /// 
 ///         // Run - Start the application.
@@ -189,46 +189,41 @@ public class Scenario : IDisposable
             }
 
             Application.Iteration += OnApplicationOnIteration;
-            Application.Driver!.ClearedContents += (sender, args) => BenchmarkResults.ClearedContentCount++;
 
-            if (Application.Driver is ConsoleDriver cd)
-            {
-                cd.Refreshed += (sender, args) =>
-                                                 {
-                                                     BenchmarkResults.RefreshedCount++;
-                                                     if (args.Value)
-                                                     {
-                                                         BenchmarkResults.UpdatedCount++;
-                                                     }
-                                                 };
-
-            }
-            Application.NotifyNewRunState += OnApplicationNotifyNewRunState;
+            Application.Driver!.ClearedContents += OnClearedContents;
+            Application.SessionBegun += OnApplicationSessionBegun;
 
 
             _stopwatch = Stopwatch.StartNew ();
         }
         else
         {
-            Application.NotifyNewRunState -= OnApplicationNotifyNewRunState;
+            Application.Driver!.ClearedContents -= OnClearedContents;
+            Application.SessionBegun -= OnApplicationSessionBegun;
             Application.Iteration -= OnApplicationOnIteration;
             BenchmarkResults.Duration = _stopwatch!.Elapsed;
             _stopwatch?.Stop ();
         }
+
+        return;
+
+        void OnClearedContents (object? sender, EventArgs args) => BenchmarkResults.ClearedContentCount++;
     }
 
-    private void OnApplicationOnIteration (object? s, IterationEventArgs a)
+    private void OnApplicationOnIteration (object? s, EventArgs<IApplication?> a)
     {
         BenchmarkResults.IterationCount++;
         if (BenchmarkResults.IterationCount > BENCHMARK_MAX_NATURAL_ITERATIONS + (_demoKeys!.Count * BENCHMARK_KEY_PACING))
         {
-            Application.RequestStop ();
+            a.Value?.RequestStop ();
         }
     }
 
-    private void OnApplicationNotifyNewRunState (object? sender, RunStateEventArgs e)
+    // BUGBUG: This is incompatible with modals. This should be using the new equivalent of Runnable.Ready 
+    // BUGBUG: which will be IsRunningChanged with newIsRunning == true
+    private void OnApplicationSessionBegun (object? sender, SessionTokenEventArgs e)
     {
-        SubscribeAllSubViews (Application.Top!);
+        SubscribeAllSubViews (Application.TopRunnableView!);
 
         _demoKeys = GetDemoKeyStrokes ();
 
@@ -248,7 +243,7 @@ public class Scenario : IDisposable
 
         return;
 
-        // Get a list of all subviews under Application.Top (and their subviews, etc.)
+        // Get a list of all subviews under Application.TopRunnable (and their subviews, etc.)
         // and subscribe to their DrawComplete event
         void SubscribeAllSubViews (View view)
         {

+ 20 - 20
Examples/UICatalog/Scenarios/Adornments.cs

@@ -11,7 +11,7 @@ public class Adornments : Scenario
     {
         Application.Init ();
 
-        Window app = new ()
+        Window appWindow = new ()
         {
             Title = GetQuitKeyAndName (),
             BorderStyle = LineStyle.None
@@ -26,9 +26,9 @@ public class Adornments : Scenario
             X = Pos.AnchorEnd ()
         };
 
-        editor.Border.Thickness = new (1, 2, 1, 1);
+        editor.Border!.Thickness = new (1, 2, 1, 1);
 
-        app.Add (editor);
+        appWindow.Add (editor);
 
         var window = new Window
         {
@@ -38,7 +38,7 @@ public class Adornments : Scenario
             Width = Dim.Fill (Dim.Func (_ => editor.Frame.Width)),
             Height = Dim.Fill ()
         };
-        app.Add (window);
+        appWindow.Add (window);
 
         var tf1 = new TextField { Width = 10, Text = "TextField" };
         var color = new ColorPicker16 { Title = "BG", BoxHeight = 1, BoxWidth = 1, X = Pos.AnchorEnd () };
@@ -60,7 +60,7 @@ public class Adornments : Scenario
         var button = new Button { X = Pos.Center (), Y = Pos.Center (), Text = "Press me!" };
 
         button.Accepting += (s, e) =>
-                             MessageBox.Query (20, 7, "Hi", $"Am I a {window.GetType ().Name}?", "Yes", "No");
+                             MessageBox.Query (appWindow.App, 20, 7, "Hi", $"Am I a {window.GetType ().Name}?", "Yes", "No");
 
         var label = new TextView
         {
@@ -71,7 +71,7 @@ public class Adornments : Scenario
             Width = 40,
             Height = 6 // TODO: Use Dim.Auto
         };
-        label.Border.Thickness = new (1, 3, 1, 1);
+        label.Border!.Thickness = new (1, 3, 1, 1);
 
         var btnButtonInWindow = new Button { X = Pos.AnchorEnd (), Y = Pos.AnchorEnd (), Text = "Button" };
 
@@ -84,13 +84,13 @@ public class Adornments : Scenario
             SchemeName = "Dialog"
         };
 
-        window.Margin.Data = "Margin";
-        window.Margin.Text = "Margin Text";
-        window.Margin.Thickness = new (0);
+        window.Margin!.Data = "Margin";
+        window.Margin!.Text = "Margin Text";
+        window.Margin!.Thickness = new (0);
 
-        window.Border.Data = "Border";
-        window.Border.Text = "Border Text";
-        window.Border.Thickness = new (0);
+        window.Border!.Data = "Border";
+        window.Border!.Text = "Border Text";
+        window.Border!.Thickness = new (0);
 
         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";
@@ -121,7 +121,7 @@ public class Adornments : Scenario
                                       Text = "text (Y = 1)",
                                       CanFocus = true
                                   };
-                                  textFieldInPadding.Accepting += (s, e) => MessageBox.Query (20, 7, "TextField", textFieldInPadding.Text, "Ok");
+                                  textFieldInPadding.Accepting += (s, e) => MessageBox.Query (appWindow.App, 20, 7, "TextField", textFieldInPadding.Text, "Ok");
                                   window.Padding.Add (textFieldInPadding);
 
                                   var btnButtonInPadding = new Button
@@ -132,16 +132,16 @@ public class Adornments : Scenario
                                       CanFocus = true,
                                       HighlightStates = MouseState.None,
                                   };
-                                  btnButtonInPadding.Accepting += (s, e) => MessageBox.Query (20, 7, "Hi", "Button in Padding Pressed!", "Ok");
+                                  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.Border!.Thickness = new (1, 1, 1, 1);
                                   window.Padding.Add (btnButtonInPadding);
 
 #if SUBVIEW_BASED_BORDER
-                                btnButtonInPadding.Border.CloseButton.Visible = true;
+                                btnButtonInPadding.Border!.CloseButton.Visible = true;
 
-                                view.Border.CloseButton.Visible = true;
-                                view.Border.CloseButton.Accept += (s, e) =>
+                                view.Border!.CloseButton.Visible = true;
+                                view.Border!.CloseButton.Accept += (s, e) =>
                                                                   {
                                                                       MessageBox.Query (20, 7, "Hi", "Window Close Button Pressed!", "Ok");
                                                                       e.Handled = true;
@@ -155,8 +155,8 @@ public class Adornments : Scenario
         editor.AutoSelectSuperView = window;
         editor.AutoSelectAdornments = true;
 
-        Application.Run (app);
-        app.Dispose ();
+        Application.Run (appWindow);
+        appWindow.Dispose ();
 
         Application.Shutdown ();
     }

+ 15 - 12
Examples/UICatalog/Scenarios/AllViewsTester.cs

@@ -28,7 +28,7 @@ public class AllViewsTester : Scenario
 
     public override void Main ()
     {
-        // Don't create a sub-win (Scenario.Win); just use Application.Top
+        // Don't create a sub-win (Scenario.Win); just use Application.TopRunnable
         Application.Init ();
 
         var app = new Window
@@ -38,7 +38,7 @@ public class AllViewsTester : Scenario
 
         // Set the BorderStyle we use for all subviews, but disable the app border thickness
         app.Border!.LineStyle = LineStyle.Heavy;
-        app.Border.Thickness = new (0);
+        app.Border!.Thickness = new (0);
 
 
         _viewClasses = GetAllViewClassesCollection ()
@@ -65,7 +65,7 @@ public class AllViewsTester : Scenario
                                                   // Dispose existing current View, if any
                                                   DisposeCurrentView ();
 
-                                                  CreateCurrentView (_viewClasses.Values.ToArray () [_classListView.SelectedItem]);
+                                                  CreateCurrentView (_viewClasses.Values.ToArray () [_classListView.SelectedItem.Value]);
 
                                                   // Force ViewToEdit to be the view and not a subview
                                                   if (_adornmentsEditor is { })
@@ -158,16 +158,13 @@ public class AllViewsTester : Scenario
 
         _eventLog = new ()
         {
-            // X = Pos.Right(_layoutEditor),
+            X = Pos.AnchorEnd () - 1,
+            Y = 0,
+            Width = 30,
+            Height = Dim.Fill (),
             SuperViewRendersLineCanvas = true
         };
         _eventLog.Border!.Thickness = new (1);
-        _eventLog.X = Pos.AnchorEnd () - 1;
-        _eventLog.Y = 0;
-
-        _eventLog.Height = Dim.Height (_classListView);
-
-        //_eventLog.Width = 30;
 
         _layoutEditor.Width = Dim.Fill (
                                         Dim.Func (
@@ -194,7 +191,6 @@ public class AllViewsTester : Scenario
             Height = Dim.Fill (),
             CanFocus = true,
             TabStop = TabBehavior.TabStop,
-            //SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Base),
             Arrangement = ViewArrangement.LeftResizable | ViewArrangement.BottomResizable | ViewArrangement.RightResizable,
             BorderStyle = LineStyle.Double,
             SuperViewRendersLineCanvas = true
@@ -224,11 +220,18 @@ public class AllViewsTester : Scenario
     {
         Debug.Assert (_curView is null);
 
+        // Skip RunnableWrapper types as they have generic constraints that cannot be satisfied
+        if (type.IsGenericType && type.GetGenericTypeDefinition().Name.StartsWith("RunnableWrapper"))
+        {
+            Logging.Warning ($"Cannot create an instance of {type.Name} because it is a RunnableWrapper with unsatisfiable generic constraints.");
+            return;
+        }
+
         // If we are to create a generic Type
         if (type.IsGenericType)
         {
             // For each of the <T> arguments
-            List<Type> typeArguments = new ();
+            List<Type> typeArguments = [];
 
             // use <object> or the original type if applicable
             foreach (Type arg in type.GetGenericArguments ())

+ 2 - 2
Examples/UICatalog/Scenarios/AnimationScenario/AnimationScenario.cs

@@ -78,7 +78,7 @@ public class AnimationScenario : Scenario
         if (!f.Exists)
         {
             Debug.WriteLine ($"Could not find {f.FullName}");
-            MessageBox.ErrorQuery ("Could not find gif", $"Could not find\n{f.FullName}", "Ok");
+            MessageBox.ErrorQuery (_imageView?.App, "Could not find gif", $"Could not find\n{f.FullName}", "Ok");
 
             return;
         }
@@ -92,7 +92,7 @@ public class AnimationScenario : Scenario
                       {
                           // When updating from a Thread/Task always use Invoke
                           Application.Invoke (
-                                              () =>
+                                              (_) =>
                                               {
                                                   _imageView.NextFrame ();
                                                   _imageView.SetNeedsDraw ();

+ 62 - 59
Examples/UICatalog/Scenarios/AnsiRequestsScenario.cs

@@ -1,6 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
+#nullable enable
 using System.Text;
 
 namespace UICatalog.Scenarios;
@@ -9,16 +7,19 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Tests")]
 public sealed class AnsiEscapeSequenceRequests : Scenario
 {
-    private GraphView _graphView;
+    private GraphView? _graphView;
 
-    private ScatterSeries _sentSeries;
-    private ScatterSeries _answeredSeries;
+    private ScatterSeries? _sentSeries;
+    private ScatterSeries? _answeredSeries;
 
     private readonly List<DateTime> _sends = new ();
 
     private readonly object _lockAnswers = new object ();
     private readonly Dictionary<DateTime, string> _answers = new ();
-    private Label _lblSummary;
+    private Label? _lblSummary;
+
+    private object? _updateTimeoutToken;
+    private object? _sendDarTimeoutToken;
 
     public override void Main ()
     {
@@ -32,7 +33,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
             CanFocus = true
         };
 
-        Tab single = new Tab ();
+        Tab single = new ();
         single.DisplayText = "Single";
         single.View = BuildSingleTab ();
 
@@ -57,6 +58,8 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
         single.View.Dispose ();
         appWindow.Dispose ();
 
+        Application.RemoveTimeout (_updateTimeoutToken!);
+        Application.RemoveTimeout (_sendDarTimeoutToken!);
         // Shutdown - Calling Application.Shutdown is required.
         Application.Shutdown ();
     }
@@ -70,7 +73,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
             CanFocus = true
         };
 
-        w.Padding.Thickness = new (1);
+        w!.Padding!.Thickness = new (1);
 
         var scrRequests = new List<string>
         {
@@ -103,7 +106,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
                                               }
 
                                               var selAnsiEscapeSequenceRequestName = scrRequests [cbRequests.SelectedItem];
-                                              AnsiEscapeSequence selAnsiEscapeSequenceRequest = null;
+                                              AnsiEscapeSequence? selAnsiEscapeSequenceRequest = null;
 
                                               switch (selAnsiEscapeSequenceRequestName)
                                               {
@@ -112,7 +115,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
 
                                                       break;
                                                   case "CSI_ReportTerminalSizeInChars":
-                                                      selAnsiEscapeSequenceRequest = EscSeqUtils.CSI_ReportTerminalSizeInChars;
+                                                      selAnsiEscapeSequenceRequest = EscSeqUtils.CSI_ReportWindowSizeInChars;
 
                                                       break;
                                                   case "CSI_RequestCursorPositionReport":
@@ -163,12 +166,12 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
                                          Value = string.IsNullOrEmpty (tfValue.Text) ? null : tfValue.Text
                                      };
 
-                                     Application.Driver.QueueAnsiRequest (
+                                     Application.Driver?.QueueAnsiRequest (
                                                                           new ()
                                                                           {
                                                                               Request = ansiEscapeSequenceRequest.Request,
                                                                               Terminator = ansiEscapeSequenceRequest.Terminator,
-                                                                              ResponseReceived = (s) => OnSuccess (s, tvResponse, tvError, tvValue, tvTerminator, lblSuccess),
+                                                                              ResponseReceived = (s) => OnSuccess (s!, tvResponse, tvError, tvValue, tvTerminator, lblSuccess),
                                                                               Abandoned = () => OnFail (tvResponse, tvError, tvValue, tvTerminator, lblSuccess)
                                                                           });
                                  };
@@ -218,21 +221,21 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
             Width = Dim.Fill ()
         };
 
-        Application.AddTimeout (
-                                TimeSpan.FromMilliseconds (1000),
-                                () =>
-                                {
-                                    lock (_lockAnswers)
-                                    {
-                                        UpdateGraph ();
+        _updateTimeoutToken = Application.AddTimeout (
+                                                      TimeSpan.FromMilliseconds (1000),
+                                                      () =>
+                                                      {
+                                                          lock (_lockAnswers)
+                                                          {
+                                                              UpdateGraph ();
 
-                                        UpdateResponses ();
-                                    }
+                                                              UpdateResponses ();
+                                                          }
 
 
 
-                                    return true;
-                                });
+                                                          return true;
+                                                      });
 
         var tv = new TextView ()
         {
@@ -266,28 +269,28 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
 
         int lastSendTime = Environment.TickCount;
         object lockObj = new object ();
-        Application.AddTimeout (
-                                TimeSpan.FromMilliseconds (50),
-                                () =>
-                                {
-                                    lock (lockObj)
-                                    {
-                                        if (cbDar.Value > 0)
-                                        {
-                                            int interval = 1000 / cbDar.Value; // Calculate the desired interval in milliseconds
-                                            int currentTime = Environment.TickCount; // Current system time in milliseconds
-
-                                            // Check if the time elapsed since the last send is greater than the interval
-                                            if (currentTime - lastSendTime >= interval)
-                                            {
-                                                SendDar (); // Send the request
-                                                lastSendTime = currentTime; // Update the last send time
-                                            }
-                                        }
-                                    }
-
-                                    return true;
-                                });
+        _sendDarTimeoutToken = Application.AddTimeout (
+                                                          TimeSpan.FromMilliseconds (50),
+                                                          () =>
+                                                          {
+                                                              lock (lockObj)
+                                                              {
+                                                                  if (cbDar.Value > 0)
+                                                                  {
+                                                                      int interval = 1000 / cbDar.Value; // Calculate the desired interval in milliseconds
+                                                                      int currentTime = Environment.TickCount; // Current system time in milliseconds
+
+                                                                      // Check if the time elapsed since the last send is greater than the interval
+                                                                      if (currentTime - lastSendTime >= interval)
+                                                                      {
+                                                                          SendDar (); // Send the request
+                                                                          lastSendTime = currentTime; // Update the last send time
+                                                                      }
+                                                                  }
+                                                              }
+
+                                                              return true;
+                                                          });
 
 
         _graphView = new GraphView ()
@@ -318,7 +321,7 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
     }
     private void UpdateResponses ()
     {
-        _lblSummary.Text = GetSummary ();
+        _lblSummary!.Text = GetSummary ();
         _lblSummary.SetNeedsDraw ();
     }
 
@@ -340,8 +343,8 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
     private void SetupGraph ()
     {
 
-        _graphView.Series.Add (_sentSeries = new ScatterSeries ());
-        _graphView.Series.Add (_answeredSeries = new ScatterSeries ());
+        _graphView!.Series.Add (_sentSeries = new ScatterSeries ());
+        _graphView!.Series.Add (_answeredSeries = new ScatterSeries ());
 
         _sentSeries.Fill = new GraphCellToRender (new Rune ('.'), new Attribute (ColorName16.BrightGreen, ColorName16.Black));
         _answeredSeries.Fill = new GraphCellToRender (new Rune ('.'), new Attribute (ColorName16.BrightRed, ColorName16.Black));
@@ -358,17 +361,17 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
 
     private void UpdateGraph ()
     {
-        _sentSeries.Points = _sends
+        _sentSeries!.Points = _sends
                              .GroupBy (ToSeconds)
                              .Select (g => new PointF (g.Key, g.Count ()))
                              .ToList ();
 
-        _answeredSeries.Points = _answers.Keys
+        _answeredSeries!.Points = _answers.Keys
                                         .GroupBy (ToSeconds)
                                         .Select (g => new PointF (g.Key, g.Count ()))
                                         .ToList ();
         //  _graphView.ScrollOffset  = new PointF(,0);
-        _graphView.SetNeedsDraw ();
+        _graphView!.SetNeedsDraw ();
 
     }
 
@@ -379,13 +382,13 @@ public sealed class AnsiEscapeSequenceRequests : Scenario
 
     private void SendDar ()
     {
-        Application.Driver.QueueAnsiRequest (
-                                             new ()
-                                             {
-                                                 Request = EscSeqUtils.CSI_SendDeviceAttributes.Request,
-                                                 Terminator = EscSeqUtils.CSI_SendDeviceAttributes.Terminator,
-                                                 ResponseReceived = HandleResponse
-                                             });
+        Application.Driver?.QueueAnsiRequest (
+                                              new ()
+                                              {
+                                                  Request = EscSeqUtils.CSI_SendDeviceAttributes.Request,
+                                                  Terminator = EscSeqUtils.CSI_SendDeviceAttributes.Terminator,
+                                                  ResponseReceived = HandleResponse!
+                                              });
         _sends.Add (DateTime.Now);
     }
 

+ 4 - 4
Examples/UICatalog/Scenarios/Arrangement.cs

@@ -183,9 +183,9 @@ public class Arrangement : Scenario
 
         datePicker.SetScheme (new Scheme (
                                           new Attribute (
-                                                         SchemeManager.GetScheme (Schemes.Toplevel).Normal.Foreground.GetBrighterColor (),
-                                                         SchemeManager.GetScheme (Schemes.Toplevel).Normal.Background.GetBrighterColor (),
-                                                         SchemeManager.GetScheme (Schemes.Toplevel).Normal.Style)));
+                                                         SchemeManager.GetScheme (Schemes.Runnable).Normal.Foreground.GetBrighterColor (),
+                                                         SchemeManager.GetScheme (Schemes.Runnable).Normal.Background.GetBrighterColor (),
+                                                         SchemeManager.GetScheme (Schemes.Runnable).Normal.Style)));
 
         TransparentView transparentView = new ()
         {
@@ -237,7 +237,7 @@ public class Arrangement : Scenario
             Width = Dim.Auto (minimumContentDim: 15),
             Height = Dim.Auto (minimumContentDim: 3),
             Title = $"Overlapped{id} _{GetNextHotKey ()}",
-            SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Toplevel),
+            SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Runnable),
             Id = $"Overlapped{id}",
             ShadowStyle = ShadowStyle.Transparent,
             BorderStyle = LineStyle.Double,

+ 23 - 23
Examples/UICatalog/Scenarios/Bars.cs

@@ -14,9 +14,9 @@ public class Bars : Scenario
     public override void Main ()
     {
         Application.Init ();
-        Toplevel app = new ();
+        Runnable app = new ();
 
-        app.Loaded += App_Loaded;
+        app.IsModalChanged += App_Loaded;
 
         Application.Run (app);
         app.Dispose ();
@@ -28,7 +28,7 @@ public class Bars : Scenario
     // QuitKey and it only sticks if changed after init
     private void App_Loaded (object sender, EventArgs e)
     {
-        Application.Top!.Title = GetQuitKeyAndName ();
+        Application.TopRunnableView!.Title = GetQuitKeyAndName ();
 
         ObservableCollection<string> eventSource = new ();
         ListView eventLog = new ListView ()
@@ -37,11 +37,11 @@ public class Bars : Scenario
             X = Pos.AnchorEnd (),
             Width = Dim.Auto (),
             Height = Dim.Fill (), // Make room for some wide things
-            SchemeName = "Toplevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (eventSource)
         };
-        eventLog.Border.Thickness = new (0, 1, 0, 0);
-        Application.Top.Add (eventLog);
+        eventLog.Border!.Thickness = new (0, 1, 0, 0);
+        Application.TopRunnableView.Add (eventLog);
 
         FrameView menuBarLikeExamples = new ()
         {
@@ -51,7 +51,7 @@ public class Bars : Scenario
             Width = Dim.Fill () - Dim.Width (eventLog),
             Height = Dim.Percent(33),
         };
-        Application.Top.Add (menuBarLikeExamples);
+        Application.TopRunnableView.Add (menuBarLikeExamples);
 
         Label label = new Label ()
         {
@@ -80,7 +80,7 @@ public class Bars : Scenario
         };
         menuBarLikeExamples.Add (label);
 
-        //bar = new MenuBarv2
+        //bar = new MenuBar
         //{
         //    Id = "menuBar",
         //    X = Pos.Right (label),
@@ -98,7 +98,7 @@ public class Bars : Scenario
             Width = Dim.Fill () - Dim.Width (eventLog),
             Height = Dim.Percent (33),
         };
-        Application.Top.Add (menuLikeExamples);
+        Application.TopRunnableView.Add (menuLikeExamples);
 
         label = new Label ()
         {
@@ -128,7 +128,7 @@ public class Bars : Scenario
         };
         menuLikeExamples.Add (label);
 
-        bar = new Menuv2
+        bar = new Menu
         {
             Id = "menu",
             X = Pos.Left (label),
@@ -147,7 +147,7 @@ public class Bars : Scenario
         };
         menuLikeExamples.Add (label);
 
-        Menuv2 popOverMenu  = new Menuv2
+        Menu popOverMenu  = new Menu
         {
             Id = "popupMenu",
             X = Pos.Left (label),
@@ -185,9 +185,9 @@ public class Bars : Scenario
 
         menuLikeExamples.Add (popOverMenu);
 
-        menuLikeExamples.MouseClick += MenuLikeExamplesMouseClick;
+        menuLikeExamples.MouseEvent += MenuLikeExamplesMouseEvent;
 
-        void MenuLikeExamplesMouseClick (object sender, MouseEventArgs e)
+        void MenuLikeExamplesMouseEvent (object _, MouseEventArgs e)
         {
             if (e.Flags.HasFlag (MouseFlags.Button3Clicked))
             {
@@ -212,7 +212,7 @@ public class Bars : Scenario
             Width = Dim.Width (menuLikeExamples),
             Height = Dim.Percent (33),
         };
-        Application.Top.Add (statusBarLikeExamples);
+        Application.TopRunnableView.Add (statusBarLikeExamples);
 
         label = new Label ()
         {
@@ -249,7 +249,7 @@ public class Bars : Scenario
         ConfigStatusBar (bar);
         statusBarLikeExamples.Add (bar);
 
-        foreach (FrameView frameView in Application.Top.SubViews.Where (f => f is FrameView)!)
+        foreach (FrameView frameView in Application.TopRunnableView.SubViews.Where (f => f is FrameView)!)
         {
             foreach (Bar barView in frameView.SubViews.Where (b => b is Bar)!)
             {
@@ -269,8 +269,8 @@ public class Bars : Scenario
 
     //private void SetupContentMenu ()
     //{
-    //    Application.Top.Add (new Label { Text = "Right Click for Context Menu", X = Pos.Center (), Y = 4 });
-    //    Application.Top.MouseClick += ShowContextMenu;
+    //    Application.TopRunnable.Add (new Label { Text = "Right Click for Context Menu", X = Pos.Center (), Y = 4 });
+    //    Application.TopRunnable.MouseClick += ShowContextMenu;
     //}
 
     //private void ShowContextMenu (object s, MouseEventEventArgs e)
@@ -309,7 +309,7 @@ public class Bars : Scenario
     //                                                  new TimeSpan (0),
     //                                                  () =>
     //                                                  {
-    //                                                      MessageBox.Query ("File", "New");
+    //                                                      MessageBox.Query (App, "File", "New");
 
     //                                                      return false;
     //                                                  });
@@ -331,7 +331,7 @@ public class Bars : Scenario
     //                                               new TimeSpan (0),
     //                                               () =>
     //                                               {
-    //                                                   MessageBox.Query ("File", "Open");
+    //                                                   MessageBox.Query (App, "File", "Open");
 
     //                                                   return false;
     //                                               });
@@ -353,7 +353,7 @@ public class Bars : Scenario
     //                                               new TimeSpan (0),
     //                                               () =>
     //                                               {
-    //                                                   MessageBox.Query ("File", "Save");
+    //                                                   MessageBox.Query (App, "File", "Save");
 
     //                                                   return false;
     //                                               });
@@ -375,7 +375,7 @@ public class Bars : Scenario
     //                                                 new TimeSpan (0),
     //                                                 () =>
     //                                                 {
-    //                                                     MessageBox.Query ("File", "Save As");
+    //                                                     MessageBox.Query (App, "File", "Save As");
 
     //                                                     return false;
     //                                                 });
@@ -383,7 +383,7 @@ public class Bars : Scenario
 
     //    contextMenu.Add (newMenu, open, save, saveAs);
 
-    //    contextMenu.KeyBindings.Add (Key.Esc, Command.QuitToplevel);
+    //    contextMenu.KeyBindings.Add (Key.Esc, Command.Quit);
 
     //    contextMenu.Initialized += Menu_Initialized;
 
@@ -555,7 +555,7 @@ public class Bars : Scenario
 
         return;
 
-        void Button_Clicked (object sender, EventArgs e) { MessageBox.Query ("Hi", $"You clicked {sender}"); }
+        void Button_Clicked (object sender, EventArgs e) { MessageBox.Query ((sender as View)?.App, "Hi", $"You clicked {sender}"); }
 
     }
 

+ 27 - 54
Examples/UICatalog/Scenarios/Buttons.cs

@@ -59,7 +59,7 @@ public class Buttons : Scenario
 
                                     if (e.Handled)
                                     {
-                                        MessageBox.ErrorQuery ("Error", "This button is no longer the Quit button; the Swap Default button is.", "_Ok");
+                                        MessageBox.ErrorQuery ((s as View)?.App, "Error", "This button is no longer the Quit button; the Swap Default button is.", "_Ok");
                                     }
                                 };
         main.Add (swapButton);
@@ -69,7 +69,7 @@ public class Buttons : Scenario
             button.Accepting += (s, e) =>
                              {
                                  string btnText = button.Text;
-                                 MessageBox.Query ("Message", $"Did you click {txt}?", "Yes", "No");
+                                 MessageBox.Query ((s as View)?.App, "Message", $"Did you click {txt}?", "Yes", "No");
                                  e.Handled = true;
                              };
         }
@@ -112,7 +112,7 @@ public class Buttons : Scenario
                  );
         button.Accepting += (s, e) =>
                          {
-                             MessageBox.Query ("Message", "Question?", "Yes", "No");
+                             MessageBox.Query ((s as View)?.App, "Message", "Question?", "Yes", "No");
                              e.Handled = true;
                          };
 
@@ -243,17 +243,17 @@ public class Buttons : Scenario
         };
         main.Add (label);
 
-        var radioGroup = new RadioGroup
+        OptionSelector<Alignment> osAlignment = new ()
         {
             X = 4,
             Y = Pos.Bottom (label) + 1,
-            SelectedItem = 2,
-            RadioLabels = new [] { "_Start", "_End", "_Center", "_Fill" },
-            Title = "_9 RadioGroup",
+            Value = Alignment.Center,
+            AssignHotKeys = true,
+            Title = "_9 OptionSelector",
             BorderStyle = LineStyle.Dotted,
             // CanFocus = false
         };
-        main.Add (radioGroup);
+        main.Add (osAlignment);
 
         // Demo changing hotkey
         string MoveHotkey (string txt)
@@ -292,9 +292,9 @@ public class Buttons : Scenario
         var moveHotKeyBtn = new Button
         {
             X = 2,
-            Y = Pos.Bottom (radioGroup) + 1,
+            Y = Pos.Bottom (osAlignment) + 1,
             Width = Dim.Width (computedFrame) - 2,
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Text = mhkb
         };
         moveHotKeyBtn.Accepting += (s, e) =>
@@ -309,9 +309,9 @@ public class Buttons : Scenario
         var moveUnicodeHotKeyBtn = new Button
         {
             X = Pos.Left (absoluteFrame) + 1,
-            Y = Pos.Bottom (radioGroup) + 1,
+            Y = Pos.Bottom (osAlignment) + 1,
             Width = Dim.Width (absoluteFrame) - 2,
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Text = muhkb
         };
         moveUnicodeHotKeyBtn.Accepting += (s, e) =>
@@ -321,48 +321,21 @@ public class Buttons : Scenario
                                        };
         main.Add (moveUnicodeHotKeyBtn);
 
-        radioGroup.SelectedItemChanged += (s, args) =>
-                                          {
-                                              switch (args.SelectedItem)
-                                              {
-                                                  case 0:
-                                                      moveBtn.TextAlignment = Alignment.Start;
-                                                      sizeBtn.TextAlignment = Alignment.Start;
-                                                      moveBtnA.TextAlignment = Alignment.Start;
-                                                      sizeBtnA.TextAlignment = Alignment.Start;
-                                                      moveHotKeyBtn.TextAlignment = Alignment.Start;
-                                                      moveUnicodeHotKeyBtn.TextAlignment = Alignment.Start;
-
-                                                      break;
-                                                  case 1:
-                                                      moveBtn.TextAlignment = Alignment.End;
-                                                      sizeBtn.TextAlignment = Alignment.End;
-                                                      moveBtnA.TextAlignment = Alignment.End;
-                                                      sizeBtnA.TextAlignment = Alignment.End;
-                                                      moveHotKeyBtn.TextAlignment = Alignment.End;
-                                                      moveUnicodeHotKeyBtn.TextAlignment = Alignment.End;
-
-                                                      break;
-                                                  case 2:
-                                                      moveBtn.TextAlignment = Alignment.Center;
-                                                      sizeBtn.TextAlignment = Alignment.Center;
-                                                      moveBtnA.TextAlignment = Alignment.Center;
-                                                      sizeBtnA.TextAlignment = Alignment.Center;
-                                                      moveHotKeyBtn.TextAlignment = Alignment.Center;
-                                                      moveUnicodeHotKeyBtn.TextAlignment = Alignment.Center;
-
-                                                      break;
-                                                  case 3:
-                                                      moveBtn.TextAlignment = Alignment.Fill;
-                                                      sizeBtn.TextAlignment = Alignment.Fill;
-                                                      moveBtnA.TextAlignment = Alignment.Fill;
-                                                      sizeBtnA.TextAlignment = Alignment.Fill;
-                                                      moveHotKeyBtn.TextAlignment = Alignment.Fill;
-                                                      moveUnicodeHotKeyBtn.TextAlignment = Alignment.Fill;
-
-                                                      break;
-                                              }
-                                          };
+        osAlignment.ValueChanged += (s, args) =>
+                                    {
+                                        if (args.Value is null)
+                                        {
+                                            return;
+                                        }
+
+                                        Alignment newValue = args.Value.Value;
+                                        moveBtn.TextAlignment = newValue;
+                                        sizeBtn.TextAlignment = newValue;
+                                        moveBtnA.TextAlignment = newValue;
+                                        sizeBtnA.TextAlignment = newValue;
+                                        moveHotKeyBtn.TextAlignment = newValue;
+                                        moveUnicodeHotKeyBtn.TextAlignment = newValue;
+                                    };
 
         label = new ()
         {

+ 12 - 36
Examples/UICatalog/Scenarios/CharacterMap/CharacterMap.cs

@@ -85,7 +85,7 @@ public class CharacterMap : Scenario
             X = Pos.Right (jumpLabel) + 1,
             Y = Pos.Y (_charMap),
             Width = 17,
-            Caption = "e.g. 01BE3 or ✈"
+            Title = "e.g. 01BE3 or ✈"
 
             //SchemeName = "Dialog"
         };
@@ -176,13 +176,13 @@ public class CharacterMap : Scenario
 
         top.Add (_categoryList);
 
-        var menu = new MenuBarv2
+        var menu = new MenuBar
         {
             Menus =
             [
                 new (
                      "_File",
-                     new MenuItemv2 []
+                     new MenuItem []
                      {
                          new (
                               "_Quit",
@@ -337,14 +337,14 @@ public class CharacterMap : Scenario
                    );
     }
 
-    private MenuItemv2 CreateMenuShowWidth ()
+    private MenuItem CreateMenuShowWidth ()
     {
         CheckBox cb = new ()
         {
             Title = "_Show Glyph Width",
             CheckedState = _charMap!.ShowGlyphWidths ? CheckState.Checked : CheckState.None
         };
-        var item = new MenuItemv2 { CommandView = cb };
+        var item = new MenuItem { CommandView = cb };
 
         item.Action += () =>
                        {
@@ -357,7 +357,7 @@ public class CharacterMap : Scenario
         return item;
     }
 
-    private MenuItemv2 CreateMenuUnicodeCategorySelector ()
+    private MenuItem CreateMenuUnicodeCategorySelector ()
     {
         // First option is "All" (no filter), followed by all UnicodeCategory names
         string [] allCategoryNames = Enum.GetNames<UnicodeCategory> ();
@@ -365,40 +365,16 @@ public class CharacterMap : Scenario
         options [0] = "All";
         Array.Copy (allCategoryNames, 0, options, 1, allCategoryNames.Length);
 
-        // TODO: When #4126 is merged update this to use OptionSelector<UnicodeCategory?>
-        var selector = new OptionSelector
-        {
-            AssignHotKeysToCheckBoxes = true,
-            Options = options
-        };
+        // TODO: Add a "None" option
+        OptionSelector<UnicodeCategory> selector = new ();
 
         _unicodeCategorySelector = selector;
 
-        // Default to "All"
-        selector.SelectedItem = 0;
+        selector.Value = null;
         _charMap!.ShowUnicodeCategory = null;
 
-        selector.SelectedItemChanged += (s, e) =>
-                                        {
-                                            int? idx = selector.SelectedItem;
-
-                                            if (idx is null)
-                                            {
-                                                return;
-                                            }
-
-                                            if (idx.Value == 0)
-                                            {
-                                                _charMap.ShowUnicodeCategory = null;
-                                            }
-                                            else
-                                            {
-                                                // Map index to UnicodeCategory (offset by 1 because 0 is "All")
-                                                UnicodeCategory cat = Enum.GetValues<UnicodeCategory> () [idx.Value - 1];
-                                                _charMap.ShowUnicodeCategory = cat;
-                                            }
-                                        };
-
-        return new() { CommandView = selector };
+        selector.ValueChanged += (_, e) => _charMap.ShowUnicodeCategory = e.Value;
+
+        return new () { CommandView = selector };
     }
 }

+ 3 - 2
Examples/UICatalog/Scenarios/ChineseUI.cs

@@ -32,8 +32,9 @@ public class ChineseUI : Scenario
 
         btn.Accepting += (s, e) =>
                       {
-                          int result = MessageBox.Query (
-                                                         "Confirm",
+                          int? result = MessageBox.Query (
+                                                          (s as View)?.App,
+                                                          "Confirm",
                                                          "Are you sure you want to quit ui?",
                                                          0,
                                                          "Yes",

+ 210 - 188
Examples/UICatalog/Scenarios/ClassExplorer.cs

@@ -1,6 +1,5 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
+#nullable enable
+
 using System.Reflection;
 using System.Text;
 
@@ -11,63 +10,45 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("TreeView")]
 public class ClassExplorer : Scenario
 {
-    private MenuItem _highlightModelTextOnly;
-    private MenuItem _miShowPrivate;
-    private TextView _textView;
-    private TreeView<object> _treeView;
+    private CheckBox? _highlightModelTextOnlyCheckBox;
+    private CheckBox? _showPrivateCheckBox;
+    private TextView? _textView;
+    private TreeView<object>? _treeView;
 
     public override void Main ()
     {
         Application.Init ();
-        var top = new Toplevel ();
 
-        var menu = new MenuBar
+        Window win = new ()
         {
-            Menus =
-            [
-                new MenuBarItem ("_File", new MenuItem [] { new ("_Quit", "", () => Quit ()) }),
-                new MenuBarItem (
-                                 "_View",
-                                 new []
-                                 {
-                                     _miShowPrivate =
-                                         new MenuItem (
-                                                       "_Include Private",
-                                                       "",
-                                                       () => ShowPrivate ()
-                                                      ) { Checked = false, CheckType = MenuItemCheckStyle.Checked },
-                                     new ("_Expand All", "", () => _treeView.ExpandAll ()),
-                                     new ("_Collapse All", "", () => _treeView.CollapseAll ())
-                                 }
-                                ),
-                new MenuBarItem (
-                                 "_Style",
-                                 new []
-                                 {
-                                     _highlightModelTextOnly = new MenuItem (
-                                                                             "_Highlight Model Text Only",
-                                                                             "",
-                                                                             () => OnCheckHighlightModelTextOnly ()
-                                                                            ) { CheckType = MenuItemCheckStyle.Checked }
-                                 }
-                                )
-            ]
+            Title = GetName (),
+            BorderStyle = LineStyle.None
         };
-        top.Add (menu);
 
-        var win = new Window
+        // MenuBar
+        MenuBar menuBar = new ();
+
+        // Search controls
+        Label lblSearch = new ()
         {
-            Title = GetName (),
-            Y = Pos.Bottom (menu)
+            Y = Pos.Bottom (menuBar),
+            Title = "Search:"
         };
 
-        _treeView = new TreeView<object> { X = 0, Y = 1, Width = Dim.Percent (50), Height = Dim.Fill () };
-
-        var lblSearch = new Label { Text = "Search" };
-        var tfSearch = new TextField { Width = 20, X = Pos.Right (lblSearch) };
+        TextField tfSearch = new ()
+        {
+            Y = Pos.Top (lblSearch),
+            X = Pos.Right (lblSearch) + 1,
+            Width = 20
+        };
 
-        win.Add (lblSearch);
-        win.Add (tfSearch);
+        // TreeView
+        _treeView = new ()
+        {
+            Y = Pos.Bottom (lblSearch),
+            Width = Dim.Percent (50),
+            Height = Dim.Fill ()
+        };
 
         TreeViewTextFilter<object> filter = new (_treeView);
         _treeView.Filter = filter;
@@ -76,7 +57,7 @@ public class ClassExplorer : Scenario
                                 {
                                     filter.Text = tfSearch.Text;
 
-                                    if (_treeView.SelectedObject != null)
+                                    if (_treeView.SelectedObject is { })
                                     {
                                         _treeView.EnsureVisible (_treeView.SelectedObject);
                                     }
@@ -87,111 +68,146 @@ public class ClassExplorer : Scenario
         _treeView.TreeBuilder = new DelegateTreeBuilder<object> (ChildGetter, CanExpand);
         _treeView.SelectionChanged += TreeView_SelectionChanged;
 
-        win.Add (_treeView);
-
-        _textView = new TextView { X = Pos.Right (_treeView), Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
-
-        win.Add (_textView);
+        // TextView for details
+        _textView = new ()
+        {
+            X = Pos.Right (_treeView),
+            Y = Pos.Top (_treeView),
+            Width = Dim.Fill (),
+            Height = Dim.Fill (),
+            ReadOnly = true,
+        };
 
-        top.Add (win);
+        // Menu setup
+        _showPrivateCheckBox = new ()
+        {
+            Title = "_Include Private"
+        };
+        _showPrivateCheckBox.CheckedStateChanged += (s, e) => ShowPrivate ();
 
-        Application.Run (top);
-        top.Dispose ();
+        _highlightModelTextOnlyCheckBox = new ()
+        {
+            Title = "_Highlight Model Text Only"
+        };
+        _highlightModelTextOnlyCheckBox.CheckedStateChanged += (s, e) => OnCheckHighlightModelTextOnly ();
+
+        menuBar.Add (
+                     new MenuBarItem (
+                                      "_File",
+                                      [
+                                          new MenuItem
+                                          {
+                                              Title = "_Quit",
+                                              Action = Quit
+                                          }
+                                      ]
+                                     )
+                    );
+
+        menuBar.Add (
+                     new MenuBarItem (
+                                      "_View",
+                                      [
+                                          new MenuItem
+                                          {
+                                              CommandView = _showPrivateCheckBox
+                                          },
+                                          new MenuItem
+                                          {
+                                              Title = "_Expand All",
+                                              Action = () => _treeView?.ExpandAll ()
+                                          },
+                                          new MenuItem
+                                          {
+                                              Title = "_Collapse All",
+                                              Action = () => _treeView?.CollapseAll ()
+                                          }
+                                      ]
+                                     )
+                    );
+
+        menuBar.Add (
+                     new MenuBarItem (
+                                      "_Style",
+                                      [
+                                          new MenuItem
+                                          {
+                                              CommandView = _highlightModelTextOnlyCheckBox
+                                          }
+                                      ]
+                                     )
+                    );
+
+        // Add views in order of visual appearance
+        win.Add (menuBar, lblSearch, tfSearch, _treeView, _textView);
+
+        Application.Run (win);
+        win.Dispose ();
         Application.Shutdown ();
     }
 
-    private bool CanExpand (object arg) { return arg is Assembly || arg is Type || arg is ShowForType; }
+    private bool CanExpand (object arg) => arg is Assembly or Type or ShowForType;
 
     private IEnumerable<object> ChildGetter (object arg)
     {
         try
         {
-            if (arg is Assembly a)
-            {
-                return a.GetTypes ();
-            }
-
-            if (arg is Type t)
-            {
-                // Note that here we cannot simply return the enum values as the same object cannot appear under multiple branches
-                return Enum.GetValues (typeof (Showable))
-                           .Cast<Showable> ()
-
-                           // Although we new the Type every time the delegate is called state is preserved because the class has appropriate equality members
-                           .Select (v => new ShowForType (v, t));
-            }
-
-            if (arg is ShowForType show)
-            {
-                switch (show.ToShow)
-                {
-                    case Showable.Properties:
-                        return show.Type.GetProperties (GetFlags ());
-                    case Showable.Constructors:
-                        return show.Type.GetConstructors (GetFlags ());
-                    case Showable.Events:
-                        return show.Type.GetEvents (GetFlags ());
-                    case Showable.Fields:
-                        return show.Type.GetFields (GetFlags ());
-                    case Showable.Methods:
-                        return show.Type.GetMethods (GetFlags ());
-                }
-            }
+            return arg switch
+                   {
+                       Assembly assembly => assembly.GetTypes (),
+                       Type type => Enum.GetValues (typeof (Showable))
+                                        .Cast<Showable> ()
+                                        .Select (v => new ShowForType (v, type)),
+                       ShowForType show => show.ToShow switch
+                                           {
+                                               Showable.Properties => show.Type.GetProperties (GetFlags ()),
+                                               Showable.Constructors => show.Type.GetConstructors (GetFlags ()),
+                                               Showable.Events => show.Type.GetEvents (GetFlags ()),
+                                               Showable.Fields => show.Type.GetFields (GetFlags ()),
+                                               Showable.Methods => show.Type.GetMethods (GetFlags ()),
+                                               _ => Enumerable.Empty<object> ()
+                                           },
+                       _ => Enumerable.Empty<object> ()
+                   };
         }
         catch (Exception)
         {
             return Enumerable.Empty<object> ();
         }
-
-        return Enumerable.Empty<object> ();
     }
 
-    private BindingFlags GetFlags ()
-    {
-        if (_miShowPrivate.Checked == true)
-        {
-            return BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
-        }
-
-        return BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
-    }
+    private BindingFlags GetFlags () =>
+        _showPrivateCheckBox?.CheckedState == CheckState.Checked
+            ? BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic
+            : BindingFlags.Instance | BindingFlags.Static | BindingFlags.Public;
 
     private string GetRepresentation (object model)
     {
         try
         {
-            if (model is Assembly ass)
-            {
-                return ass.GetName ().Name;
-            }
-
-            if (model is PropertyInfo p)
-            {
-                return p.Name;
-            }
-
-            if (model is FieldInfo f)
-            {
-                return f.Name;
-            }
-
-            if (model is EventInfo ei)
-            {
-                return ei.Name;
-            }
+            return model switch
+                   {
+                       Assembly assembly => assembly.GetName ().Name ?? string.Empty,
+                       PropertyInfo propertyInfo => propertyInfo.Name,
+                       FieldInfo fieldInfo => fieldInfo.Name,
+                       EventInfo eventInfo => eventInfo.Name,
+                       _ => model.ToString () ?? string.Empty
+                   };
         }
         catch (Exception ex)
         {
             return ex.Message;
         }
-
-        return model.ToString ();
     }
 
     private void OnCheckHighlightModelTextOnly ()
     {
-        _treeView.Style.HighlightModelTextOnly = !_treeView.Style.HighlightModelTextOnly;
-        _highlightModelTextOnly.Checked = _treeView.Style.HighlightModelTextOnly;
+        if (_treeView is null)
+        {
+            return;
+        }
+
+        _treeView.Style.HighlightModelTextOnly = _highlightModelTextOnlyCheckBox?.CheckedState == CheckState.Checked;
         _treeView.SetNeedsDraw ();
     }
 
@@ -199,17 +215,21 @@ public class ClassExplorer : Scenario
 
     private void ShowPrivate ()
     {
-        _miShowPrivate.Checked = !_miShowPrivate.Checked;
-        _treeView.RebuildTree ();
-        _treeView.SetFocus ();
+        _treeView?.RebuildTree ();
+        _treeView?.SetFocus ();
     }
 
-    private void TreeView_SelectionChanged (object sender, SelectionChangedEventArgs<object> e)
+    private void TreeView_SelectionChanged (object? sender, SelectionChangedEventArgs<object> e)
     {
-        object val = e.NewValue;
+        if (_treeView is null || _textView is null)
+        {
+            return;
+        }
+
+        object? val = e.NewValue;
         object [] all = _treeView.GetAllSelectedObjects ().ToArray ();
 
-        if (val == null || val is ShowForType)
+        if (val is null or ShowForType)
         {
             return;
         }
@@ -218,69 +238,73 @@ public class ClassExplorer : Scenario
         {
             if (all.Length > 1)
             {
-                _textView.Text = all.Length + " Objects";
+                _textView.Text = $"{all.Length} Objects";
             }
             else
             {
-                var sb = new StringBuilder ();
+                StringBuilder sb = new ();
 
-                // tell the user about the currently selected tree node
-                sb.AppendLine (e.NewValue.GetType ().Name);
+                sb.AppendLine (e.NewValue?.GetType ().Name ?? string.Empty);
 
-                if (val is Assembly ass)
+                switch (val)
                 {
-                    sb.AppendLine ($"Location:{ass.Location}");
-                    sb.AppendLine ($"FullName:{ass.FullName}");
-                }
+                    case Assembly assembly:
+                        sb.AppendLine ($"Location:{assembly.Location}");
+                        sb.AppendLine ($"FullName:{assembly.FullName}");
 
-                if (val is PropertyInfo p)
-                {
-                    sb.AppendLine ($"Name:{p.Name}");
-                    sb.AppendLine ($"Type:{p.PropertyType}");
-                    sb.AppendLine ($"CanWrite:{p.CanWrite}");
-                    sb.AppendLine ($"CanRead:{p.CanRead}");
-                }
+                        break;
 
-                if (val is FieldInfo f)
-                {
-                    sb.AppendLine ($"Name:{f.Name}");
-                    sb.AppendLine ($"Type:{f.FieldType}");
-                }
+                    case PropertyInfo propertyInfo:
+                        sb.AppendLine ($"Name:{propertyInfo.Name}");
+                        sb.AppendLine ($"Type:{propertyInfo.PropertyType}");
+                        sb.AppendLine ($"CanWrite:{propertyInfo.CanWrite}");
+                        sb.AppendLine ($"CanRead:{propertyInfo.CanRead}");
 
-                if (val is EventInfo ev)
-                {
-                    sb.AppendLine ($"Name:{ev.Name}");
-                    sb.AppendLine ("Parameters:");
-
-                    foreach (ParameterInfo parameter in ev.EventHandlerType.GetMethod ("Invoke")
-                                                          .GetParameters ())
-                    {
-                        sb.AppendLine ($"  {parameter.ParameterType} {parameter.Name}");
-                    }
-                }
+                        break;
 
-                if (val is MethodInfo method)
-                {
-                    sb.AppendLine ($"Name:{method.Name}");
-                    sb.AppendLine ($"IsPublic:{method.IsPublic}");
-                    sb.AppendLine ($"IsStatic:{method.IsStatic}");
-                    sb.AppendLine ($"Parameters:{(method.GetParameters ().Any () ? "" : "None")}");
-
-                    foreach (ParameterInfo parameter in method.GetParameters ())
-                    {
-                        sb.AppendLine ($"  {parameter.ParameterType} {parameter.Name}");
-                    }
-                }
+                    case FieldInfo fieldInfo:
+                        sb.AppendLine ($"Name:{fieldInfo.Name}");
+                        sb.AppendLine ($"Type:{fieldInfo.FieldType}");
 
-                if (val is ConstructorInfo ctor)
-                {
-                    sb.AppendLine ($"Name:{ctor.Name}");
-                    sb.AppendLine ($"Parameters:{(ctor.GetParameters ().Any () ? "" : "None")}");
+                        break;
+
+                    case EventInfo eventInfo:
+                        sb.AppendLine ($"Name:{eventInfo.Name}");
+                        sb.AppendLine ("Parameters:");
+
+                        if (eventInfo.EventHandlerType?.GetMethod ("Invoke") is { } invokeMethod)
+                        {
+                            foreach (ParameterInfo parameter in invokeMethod.GetParameters ())
+                            {
+                                sb.AppendLine ($"  {parameter.ParameterType} {parameter.Name}");
+                            }
+                        }
 
-                    foreach (ParameterInfo parameter in ctor.GetParameters ())
-                    {
-                        sb.AppendLine ($"  {parameter.ParameterType} {parameter.Name}");
-                    }
+                        break;
+
+                    case MethodInfo methodInfo:
+                        sb.AppendLine ($"Name:{methodInfo.Name}");
+                        sb.AppendLine ($"IsPublic:{methodInfo.IsPublic}");
+                        sb.AppendLine ($"IsStatic:{methodInfo.IsStatic}");
+                        sb.AppendLine ($"Parameters:{(methodInfo.GetParameters ().Length > 0 ? string.Empty : "None")}");
+
+                        foreach (ParameterInfo parameter in methodInfo.GetParameters ())
+                        {
+                            sb.AppendLine ($"  {parameter.ParameterType} {parameter.Name}");
+                        }
+
+                        break;
+
+                    case ConstructorInfo constructorInfo:
+                        sb.AppendLine ($"Name:{constructorInfo.Name}");
+                        sb.AppendLine ($"Parameters:{(constructorInfo.GetParameters ().Length > 0 ? string.Empty : "None")}");
+
+                        foreach (ParameterInfo parameter in constructorInfo.GetParameters ())
+                        {
+                            sb.AppendLine ($"  {parameter.ParameterType} {parameter.Name}");
+                        }
+
+                        break;
                 }
 
                 _textView.Text = sb.ToString ().Replace ("\r\n", "\n");
@@ -303,7 +327,7 @@ public class ClassExplorer : Scenario
         Methods
     }
 
-    private class ShowForType
+    private sealed class ShowForType
     {
         public ShowForType (Showable toShow, Type type)
         {
@@ -314,13 +338,11 @@ public class ClassExplorer : Scenario
         public Showable ToShow { get; }
         public Type Type { get; }
 
-        // Make sure to implement Equals methods on your objects if you intend to return new instances every time in ChildGetter
-        public override bool Equals (object obj)
-        {
-            return obj is ShowForType type && EqualityComparer<Type>.Default.Equals (Type, type.Type) && ToShow == type.ToShow;
-        }
+        public override bool Equals (object? obj) =>
+            obj is ShowForType type && EqualityComparer<Type>.Default.Equals (Type, type.Type) && ToShow == type.ToShow;
+
+        public override int GetHashCode () => HashCode.Combine (Type, ToShow);
 
-        public override int GetHashCode () { return HashCode.Combine (Type, ToShow); }
-        public override string ToString () { return ToShow.ToString (); }
+        public override string ToString () => ToShow.ToString ();
     }
 }

+ 2 - 2
Examples/UICatalog/Scenarios/Clipping.cs

@@ -118,7 +118,7 @@ public class Clipping : Scenario
             Height = Dim.Auto (minimumContentDim: 4),
             Width = Dim.Auto (minimumContentDim: 14),
             Title = $"Overlapped{id} _{GetNextHotKey ()}",
-            SchemeName = SchemeManager.SchemesToSchemeName(Schemes.Toplevel),
+            SchemeName = SchemeManager.SchemesToSchemeName(Schemes.Runnable),
             Id = $"Overlapped{id}",
             ShadowStyle = ShadowStyle.Transparent,
             BorderStyle = LineStyle.Double,
@@ -151,7 +151,7 @@ public class Clipping : Scenario
         //tiled.Padding.Thickness = new (1);
         //tiled.Padding.Diagnostics =  ViewDiagnosticFlags.Thickness;
 
-        //tiled.Margin.Thickness = new (1);
+        //tiled.Margin!.Thickness = new (1);
 
         FrameView fv = new ()
         {

+ 169 - 112
Examples/UICatalog/Scenarios/CollectionNavigatorTester.cs

@@ -1,14 +1,13 @@
-using System;
-using System.Collections.Generic;
+#nullable enable
+
 using System.Collections.ObjectModel;
-using System.Linq;
 
 namespace UICatalog.Scenarios;
 
 [ScenarioMetadata (
-                               "Collection Navigator",
-                               "Demonstrates keyboard navigation in ListView & TreeView (CollectionNavigator)."
-                           )]
+                      "Collection Navigator",
+                      "Demonstrates keyboard navigation in ListView & TreeView (CollectionNavigator)."
+                  )]
 [ScenarioCategory ("Controls")]
 [ScenarioCategory ("ListView")]
 [ScenarioCategory ("TreeView")]
@@ -16,120 +15,165 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Mouse and Keyboard")]
 public class CollectionNavigatorTester : Scenario
 {
-    private ObservableCollection<string> _items = new ObservableCollection<string> (new ObservableCollection<string> ()
-    {
-        "a",
-        "b",
-        "bb",
-        "c",
-        "ccc",
-        "ccc",
-        "cccc",
-        "ddd",
-        "dddd",
-        "dddd",
-        "ddddd",
-        "dddddd",
-        "ddddddd",
-        "this",
-        "this is a test",
-        "this was a test",
-        "this and",
-        "that and that",
-        "the",
-        "think",
-        "thunk",
-        "thunks",
-        "zip",
-        "zap",
-        "zoo",
-        "@jack",
-        "@sign",
-        "@at",
-        "@ateme",
-        "n@",
-        "n@brown",
-        ".net",
-        "$100.00",
-        "$101.00",
-        "$101.10",
-        "$101.11",
-        "$200.00",
-        "$210.99",
-        "$$",
-        "apricot",
-        "arm",
-        "丗丙业丞",
-        "丗丙丛",
-        "text",
-        "egg",
-        "candle",
-        " <- space",
-        "\t<- tab",
-        "\n<- newline",
-        "\r<- formfeed",
-        "q",
-        "quit",
-        "quitter"
-    }.ToList ());
-
-    private Toplevel top;
-    private ListView _listView;
-    private TreeView _treeView;
-
-    // Don't create a Window, just return the top-level view
+    private ObservableCollection<string> _items = new (
+                                                       [
+                                                           "a",
+                                                           "b",
+                                                           "bb",
+                                                           "c",
+                                                           "ccc",
+                                                           "ccc",
+                                                           "cccc",
+                                                           "ddd",
+                                                           "dddd",
+                                                           "dddd",
+                                                           "ddddd",
+                                                           "dddddd",
+                                                           "ddddddd",
+                                                           "this",
+                                                           "this is a test",
+                                                           "this was a test",
+                                                           "this and",
+                                                           "that and that",
+                                                           "the",
+                                                           "think",
+                                                           "thunk",
+                                                           "thunks",
+                                                           "zip",
+                                                           "zap",
+                                                           "zoo",
+                                                           "@jack",
+                                                           "@sign",
+                                                           "@at",
+                                                           "@ateme",
+                                                           "n@",
+                                                           "n@brown",
+                                                           ".net",
+                                                           "$100.00",
+                                                           "$101.00",
+                                                           "$101.10",
+                                                           "$101.11",
+                                                           "$200.00",
+                                                           "$210.99",
+                                                           "$$",
+                                                           "apricot",
+                                                           "arm",
+                                                           "丗丙业丞",
+                                                           "丗丙丛",
+                                                           "text",
+                                                           "egg",
+                                                           "candle",
+                                                           " <- space",
+                                                           "\t<- tab",
+                                                           "\n<- newline",
+                                                           "\r<- formfeed",
+                                                           "q",
+                                                           "quit",
+                                                           "quitter"
+                                                       ]
+                                                      );
+
+    private Window? _top;
+    private ListView? _listView;
+    private TreeView? _treeView;
+    private CheckBox? _allowMarkingCheckBox;
+    private CheckBox? _allowMultiSelectionCheckBox;
+
     public override void Main ()
     {
         Application.Init ();
-        top = new Toplevel { SchemeName = "Base" };
 
-        var allowMarking = new MenuItem ("Allow _Marking", "", null)
+        Window top = new ()
         {
-            CheckType = MenuItemCheckStyle.Checked, Checked = false
+            SchemeName = "Base"
         };
-        allowMarking.Action = () => allowMarking.Checked = _listView.AllowsMarking = !_listView.AllowsMarking;
+        _top = top;
+
+        // MenuBar
+        MenuBar menu = new ();
 
-        var allowMultiSelection = new MenuItem ("Allow Multi _Selection", "", null)
+        _allowMarkingCheckBox = new ()
         {
-            CheckType = MenuItemCheckStyle.Checked, Checked = false
+            Title = "Allow _Marking"
         };
 
-        allowMultiSelection.Action = () =>
-                                         allowMultiSelection.Checked =
-                                             _listView.AllowsMultipleSelection = !_listView.AllowsMultipleSelection;
-        allowMultiSelection.CanExecute = () => (bool)allowMarking.Checked;
+        _allowMarkingCheckBox.CheckedStateChanged += (s, e) =>
+                                                     {
+                                                         if (_listView is { })
+                                                         {
+                                                             _listView.AllowsMarking = _allowMarkingCheckBox.CheckedState == CheckState.Checked;
+                                                         }
 
-        var menu = new MenuBar
+                                                         if (_allowMultiSelectionCheckBox is { })
+                                                         {
+                                                             _allowMultiSelectionCheckBox.Enabled = _allowMarkingCheckBox.CheckedState == CheckState.Checked;
+                                                         }
+                                                     };
+
+        _allowMultiSelectionCheckBox = new ()
         {
-            Menus =
-            [
-                new MenuBarItem (
-                                 "_Configure",
-                                 new []
-                                 {
-                                     allowMarking,
-                                     allowMultiSelection,
-                                     null,
-                                     new (
-                                          "_Quit",
-                                          $"{Application.QuitKey}",
-                                          () => Quit (),
-                                          null,
-                                          null,
-                                          (KeyCode)Application.QuitKey
-                                         )
-                                 }
-                                ),
-                new MenuBarItem ("_Quit", $"{Application.QuitKey}", () => Quit ())
-            ]
+            Title = "Allow Multi _Selection",
+            Enabled = false
         };
 
+        _allowMultiSelectionCheckBox.CheckedStateChanged += (s, e) =>
+                                                            {
+                                                                if (_listView is { })
+                                                                {
+                                                                    _listView.AllowsMultipleSelection =
+                                                                        _allowMultiSelectionCheckBox.CheckedState == CheckState.Checked;
+                                                                }
+                                                            };
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_Configure",
+                                   [
+                                       new MenuItem
+                                       {
+                                           CommandView = _allowMarkingCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _allowMultiSelectionCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Quit",
+                                           Key = Application.QuitKey,
+                                           Action = Quit
+                                       }
+                                   ]
+                                  )
+                 );
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_Quit",
+                                   [
+                                       new MenuItem
+                                       {
+                                           Title = "_Quit",
+                                           Key = Application.QuitKey,
+                                           Action = Quit
+                                       }
+                                   ]
+                                  )
+                 );
+
         top.Add (menu);
 
         _items = new (_items.OrderBy (i => i, StringComparer.OrdinalIgnoreCase));
 
         CreateListView ();
-        var vsep = new Line { Orientation = Orientation.Vertical, X = Pos.Right (_listView), Y = 1, Height = Dim.Fill () };
+
+        Line vsep = new ()
+        {
+            Orientation = Orientation.Vertical,
+            X = Pos.Right (_listView!),
+            Y = 1,
+            Height = Dim.Fill ()
+        };
         top.Add (vsep);
         CreateTreeView ();
 
@@ -140,7 +184,12 @@ public class CollectionNavigatorTester : Scenario
 
     private void CreateListView ()
     {
-        var label = new Label
+        if (_top is null)
+        {
+            return;
+        }
+
+        Label label = new ()
         {
             Text = "ListView",
             TextAlignment = Alignment.Center,
@@ -149,9 +198,9 @@ public class CollectionNavigatorTester : Scenario
             Width = Dim.Percent (50),
             Height = 1
         };
-        top.Add (label);
+        _top.Add (label);
 
-        _listView = new ListView
+        _listView = new ()
         {
             X = 0,
             Y = Pos.Bottom (label),
@@ -160,7 +209,7 @@ public class CollectionNavigatorTester : Scenario
             AllowsMarking = false,
             AllowsMultipleSelection = false
         };
-        top.Add (_listView);
+        _top.Add (_listView);
 
         _listView.SetSource (_items);
 
@@ -169,7 +218,12 @@ public class CollectionNavigatorTester : Scenario
 
     private void CreateTreeView ()
     {
-        var label = new Label
+        if (_top is null || _listView is null)
+        {
+            return;
+        }
+
+        Label label = new ()
         {
             Text = "TreeView",
             TextAlignment = Alignment.Center,
@@ -178,23 +232,26 @@ public class CollectionNavigatorTester : Scenario
             Width = Dim.Percent (50),
             Height = 1
         };
-        top.Add (label);
+        _top.Add (label);
 
-        _treeView = new TreeView
+        _treeView = new ()
         {
-            X = Pos.Right (_listView) + 1, Y = Pos.Bottom (label), Width = Dim.Fill (), Height = Dim.Fill ()
+            X = Pos.Right (_listView) + 1,
+            Y = Pos.Bottom (label),
+            Width = Dim.Fill (),
+            Height = Dim.Fill ()
         };
         _treeView.Style.HighlightModelTextOnly = true;
-        top.Add (_treeView);
+        _top.Add (_treeView);
 
-        var root = new TreeNode ("IsLetterOrDigit examples");
+        TreeNode root = new ("IsLetterOrDigit examples");
 
         root.Children = _items.Where (i => char.IsLetterOrDigit (i [0]))
                               .Select (i => new TreeNode (i))
                               .Cast<ITreeNode> ()
                               .ToList ();
         _treeView.AddObject (root);
-        root = new TreeNode ("Non-IsLetterOrDigit examples");
+        root = new ("Non-IsLetterOrDigit examples");
 
         root.Children = _items.Where (i => !char.IsLetterOrDigit (i [0]))
                               .Select (i => new TreeNode (i))

+ 47 - 16
Examples/UICatalog/Scenarios/ColorPicker.cs

@@ -3,7 +3,7 @@ using System.Collections.Generic;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("ColorPicker", "Color Picker.")]
+[ScenarioMetadata ("ColorPicker", "Color Picker and TrueColor demonstration.")]
 [ScenarioCategory ("Colors")]
 [ScenarioCategory ("Controls")]
 public class ColorPickers : Scenario
@@ -125,26 +125,25 @@ public class ColorPickers : Scenario
         app.Add (_demoView);
 
 
-        // Radio for switching color models
-        var rgColorModel = new RadioGroup ()
+        var osColorModel = new OptionSelector ()
         {
             Y = Pos.Bottom (_demoView),
             Width = Dim.Auto (),
             Height = Dim.Auto (),
-            RadioLabels = new []
-            {
+            Labels =
+            [
                 "_RGB",
                 "_HSV",
                 "H_SL",
                 "_16 Colors"
-            },
-            SelectedItem = (int)foregroundColorPicker.Style.ColorModel,
+            ],
+            Value = (int)foregroundColorPicker.Style.ColorModel,
         };
 
-        rgColorModel.SelectedItemChanged += (_, e) =>
+        osColorModel.ValueChanged += (_, e) =>
                                             {
                                                 // 16 colors
-                                                if (e.SelectedItem == 3)
+                                                if (e.Value == 3)
                                                 {
 
                                                     foregroundColorPicker16.Visible = true;
@@ -161,12 +160,17 @@ public class ColorPickers : Scenario
                                                 {
                                                     foregroundColorPicker16.Visible = false;
                                                     foregroundColorPicker.Visible = true;
-                                                    foregroundColorPicker.Style.ColorModel = (ColorModel)e.SelectedItem;
-                                                    foregroundColorPicker.ApplyStyleChanges ();
 
-                                                    backgroundColorPicker16.Visible = false;
-                                                    backgroundColorPicker.Visible = true;
-                                                    backgroundColorPicker.Style.ColorModel = (ColorModel)e.SelectedItem;
+                                                    if (e.Value is { })
+                                                    {
+                                                        foregroundColorPicker.Style.ColorModel = (ColorModel)e.Value;
+                                                        foregroundColorPicker.ApplyStyleChanges ();
+
+                                                        backgroundColorPicker16.Visible = false;
+                                                        backgroundColorPicker.Visible = true;
+                                                        backgroundColorPicker.Style.ColorModel = (ColorModel)e.Value;
+                                                    }
+
                                                     backgroundColorPicker.ApplyStyleChanges ();
 
 
@@ -176,13 +180,13 @@ public class ColorPickers : Scenario
                                                 }
                                             };
 
-        app.Add (rgColorModel);
+        app.Add (osColorModel);
 
         // Checkbox for switching show text fields on and off
         var cbShowTextFields = new CheckBox ()
         {
             Text = "Show _Text Fields",
-            Y = Pos.Bottom (rgColorModel) + 1,
+            Y = Pos.Bottom (osColorModel) + 1,
             Width = Dim.Auto (),
             Height = Dim.Auto (),
             CheckedState = foregroundColorPicker.Style.ShowTextFields ? CheckState.Checked : CheckState.UnChecked,
@@ -216,6 +220,33 @@ public class ColorPickers : Scenario
                                            };
         app.Add (cbShowName);
 
+        var lblDriverName = new Label
+        {
+            Y = Pos.Bottom (cbShowName) + 1, Text = $"Driver is `{Application.Driver?.GetName ()}`:"
+        };
+        bool canTrueColor = Application.Driver?.SupportsTrueColor ?? false;
+
+        var cbSupportsTrueColor = new CheckBox
+        {
+            X = Pos.Right (lblDriverName) + 1,
+            Y = Pos.Top (lblDriverName),
+            CheckedState = canTrueColor ? CheckState.Checked : CheckState.UnChecked,
+            CanFocus = false,
+            Enabled = false,
+            Text = "SupportsTrueColor"
+        };
+        app.Add (cbSupportsTrueColor);
+
+        var cbUseTrueColor = new CheckBox
+        {
+            X = Pos.Right (cbSupportsTrueColor) + 1,
+            Y = Pos.Top (lblDriverName),
+            CheckedState = Application.Force16Colors ? CheckState.Checked : CheckState.UnChecked,
+            Enabled = canTrueColor,
+            Text = "Force16Colors"
+        };
+        cbUseTrueColor.CheckedStateChanging += (_, evt) => { Application.Force16Colors = evt.Result == CheckState.Checked; };
+        app.Add (lblDriverName, cbSupportsTrueColor, cbUseTrueColor);
         // Set default colors.
         foregroundColorPicker.SelectedColor = _demoView.SuperView!.GetAttributeForRole (VisualRole.Normal).Foreground.GetClosestNamedColor16 ();
         backgroundColorPicker.SelectedColor = _demoView.SuperView.GetAttributeForRole (VisualRole.Normal).Background.GetClosestNamedColor16 ();

+ 17 - 6
Examples/UICatalog/Scenarios/CombiningMarks.cs

@@ -8,15 +8,16 @@ public class CombiningMarks : Scenario
     public override void Main ()
     {
         Application.Init ();
-        var top = new Toplevel ();
+        var top = new Runnable ();
 
         top.DrawComplete += (s, e) =>
         {
             // Forces reset _lineColsOffset because we're dealing with direct draw
-            Application.Top!.SetNeedsDraw ();
+            Application.TopRunnableView!.SetNeedsDraw ();
 
             var i = -1;
-            top.AddStr ("Terminal.Gui only supports combining marks that normalize. See Issue #2616.");
+            top.Move (0, ++i);
+            top.AddStr ("Terminal.Gui supports all combining sequences that can be rendered as an unique grapheme.");
             top.Move (0, ++i);
             top.AddStr ("\u0301<- \"\\u0301\" using AddStr.");
             top.Move (0, ++i);
@@ -38,7 +39,7 @@ public class CombiningMarks : Scenario
             top.AddRune ('\u0301');
             top.AddRune ('\u0328');
             top.AddRune (']');
-            top.AddStr ("<- \"[a\\u0301\\u0301\\u0328]\" using AddRune for each.");
+            top.AddStr ("<- \"[a\\u0301\\u0301\\u0328]\" using AddRune for each. Avoid use AddRune for combining sequences because may result with empty blocks at end.");
             top.Move (0, ++i);
             top.AddStr ("[a\u0301\u0301\u0328]<- \"[a\\u0301\\u0301\\u0328]\" using AddStr.");
             top.Move (0, ++i);
@@ -58,9 +59,9 @@ public class CombiningMarks : Scenario
             top.Move (0, ++i);
             top.AddStr ("From now on we are using TextFormatter");
             TextFormatter tf = new () { Text = "[e\u0301\u0301\u0328]<- \"[e\\u0301\\u0301\\u0328]\" using TextFormatter." };
-            tf.Draw (new (0, ++i, tf.Text.Length, 1), top.GetAttributeForRole (VisualRole.Normal), top.GetAttributeForRole (VisualRole.Normal));
+            tf.Draw (driver: Application.Driver, screen: new (0, ++i, tf.Text.Length, 1), normalColor: top.GetAttributeForRole (VisualRole.Normal), hotColor: top.GetAttributeForRole (VisualRole.Normal));
             tf.Text = "[e\u0328\u0301]<- \"[e\\u0328\\u0301]\" using TextFormatter.";
-            tf.Draw (new (0, ++i, tf.Text.Length, 1), top.GetAttributeForRole (VisualRole.Normal), top.GetAttributeForRole (VisualRole.Normal));
+            tf.Draw (driver: Application.Driver, screen: new (0, ++i, tf.Text.Length, 1), normalColor: top.GetAttributeForRole (VisualRole.Normal), hotColor: top.GetAttributeForRole (VisualRole.Normal));
             i++;
             top.Move (0, ++i);
             top.AddStr ("From now on we are using Surrogate pairs with combining diacritics");
@@ -82,6 +83,16 @@ public class CombiningMarks : Scenario
             top.AddStr ("[\U0001F468\U0001F469\U0001F9D2]<- \"[\\U0001F468\\U0001F469\\U0001F9D2]\" using AddStr.");
             top.Move (0, ++i);
             top.AddStr ("[\U0001F468\u200D\U0001F469\u200D\U0001F9D2]<- \"[\\U0001F468\\u200D\\U0001F469\\u200D\\U0001F9D2]\" using AddStr.");
+            top.Move (0, ++i);
+            top.AddStr ("[\U0001F468\u200D\U0001F469\u200D\U0001F467\u200D\U0001F466]<- \"[\\U0001F468\\u200D\\U0001F469\\u200D\\U0001F467\\u200D\\U0001F466]\" using AddStr.");
+            top.Move (0, ++i);
+            top.AddStr ("[\u0e32\u0e33]<- \"[\\u0e32\\u0e33]\" using AddStr.");
+            top.Move (0, ++i);
+            top.AddStr ("[\U0001F469\u200D\u2764\uFE0F\u200D\U0001F48B\u200D\U0001F468]<- \"[\\U0001F469\\u200D\\u2764\\uFE0F\\u200D\\U0001F48B\\u200D\\U0001F468]\" using AddStr.");
+            top.Move (0, ++i);
+            top.AddStr ("[\u0061\uFE20\u0065\uFE21]<- \"[\\u0061\\uFE20\\u0065\\uFE21]\" using AddStr.");
+            top.Move (0, ++i);
+            top.AddStr ("[\u1100\uD7B0]<- \"[\\u1100\\uD7B0]\" using AddStr.");
         };
 
         Application.Run (top);

+ 3 - 3
Examples/UICatalog/Scenarios/ComboBoxIteration.cs

@@ -25,7 +25,7 @@ public class ComboBoxIteration : Scenario
 
         var lbComboBox = new Label
         {
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             X = Pos.Right (lbListView) + 1,
             Width = Dim.Percent (40)
         };
@@ -42,8 +42,8 @@ public class ComboBoxIteration : Scenario
 
         listview.SelectedItemChanged += (s, e) =>
                                         {
-                                            lbListView.Text = items [e.Item];
-                                            comboBox.SelectedItem = e.Item;
+                                            lbListView.Text = items [e.Item!.Value];
+                                            comboBox.SelectedItem = e.Item.Value;
                                         };
 
         comboBox.SelectedItemChanged += (sender, text) =>

+ 1 - 1
Examples/UICatalog/Scenarios/ComputedLayout.cs

@@ -280,7 +280,7 @@ public class ComputedLayout : Scenario
             Y = Pos.Percent (50),
             Width = Dim.Percent (80),
             Height = Dim.Percent (10),
-            SchemeName = "TopLevel"
+            SchemeName = "Runnable"
         };
 
         textView.Text =

+ 5 - 5
Examples/UICatalog/Scenarios/ConfigurationEditor.cs

@@ -60,7 +60,7 @@ public class ConfigurationEditor : Scenario
 
         win.Add (_tabView, statusBar);
 
-        win.Loaded += (s, a) =>
+        win.IsModalChanged += (s, a) =>
                       {
                           Open ();
                       };
@@ -75,7 +75,7 @@ public class ConfigurationEditor : Scenario
 
         void ConfigurationManagerOnApplied (object? sender, ConfigurationManagerEventArgs e)
         {
-            Application.Top?.SetNeedsDraw ();
+            Application.TopRunnableView?.SetNeedsDraw ();
         }
     }
     public void Save ()
@@ -153,9 +153,9 @@ public class ConfigurationEditor : Scenario
                 continue;
             }
 
-            int result = MessageBox.Query (
+            int? result = MessageBox.Query (editor?.App,
                                            "Save Changes",
-                                           $"Save changes to {editor.FileInfo!.Name}",
+                                           $"Save changes to {editor?.FileInfo!.Name}",
                                            "_Yes",
                                            "_No",
                                            "_Cancel"
@@ -164,7 +164,7 @@ public class ConfigurationEditor : Scenario
             switch (result)
             {
                 case 0:
-                    editor.Save ();
+                    editor?.Save ();
 
                     break;
 

+ 77 - 69
Examples/UICatalog/Scenarios/ContextMenus.cs

@@ -1,5 +1,7 @@
-using System.Globalization;
+#nullable enable
+using System.Globalization;
 using JetBrains.Annotations;
+// ReSharper disable AccessToDisposedClosure
 
 namespace UICatalog.Scenarios;
 
@@ -7,78 +9,89 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Menus")]
 public class ContextMenus : Scenario
 {
-    [CanBeNull]
-    private PopoverMenu _winContextMenu;
-    private TextField _tfTopLeft, _tfTopRight, _tfMiddle, _tfBottomLeft, _tfBottomRight;
-    private readonly List<CultureInfo> _cultureInfos = Application.SupportedCultures;
+    private PopoverMenu? _winContextMenu;
+    private TextField? _tfTopLeft, _tfTopRight, _tfMiddle, _tfBottomLeft, _tfBottomRight;
+    private readonly List<CultureInfo>? _cultureInfos = Application.SupportedCultures;
     private readonly Key _winContextMenuKey = Key.Space.WithCtrl;
 
+    private Window? _appWindow;
+
     public override void Main ()
     {
         // Init
         Application.Init ();
 
         // Setup - Create a top-level application window and configure it.
-        Window appWindow = new ()
+        _appWindow = new ()
         {
             Title = GetQuitKeyAndName (),
             Arrangement = ViewArrangement.Fixed,
-            SchemeName = "Toplevel"
+            SchemeName = "Runnable"
         };
 
-        var text = "Context Menu";
-        var width = 20;
+        _appWindow.Initialized += AppWindowOnInitialized;
 
-        CreateWinContextMenu ();
+        // Run - Start the application.
+        Application.Run (_appWindow);
+        _appWindow.Dispose ();
+        _appWindow.KeyDown -= OnAppWindowOnKeyDown;
+        _appWindow.MouseClick -= OnAppWindowOnMouseClick;
+        _winContextMenu?.Dispose ();
 
-        var label = new Label
-        {
-            X = Pos.Center (), Y = 1, Text = $"Press '{_winContextMenuKey}' to open the Window context menu."
-        };
-        appWindow.Add (label);
+        // Shutdown - Calling Application.Shutdown is required.
+        Application.Shutdown ();
+
+        return;
 
-        label = new ()
+        void AppWindowOnInitialized (object? sender, EventArgs e)
         {
-            X = Pos.Center (),
-            Y = Pos.Bottom (label),
-            Text = $"Press '{PopoverMenu.DefaultKey}' to open the TextField context menu."
-        };
-        appWindow.Add (label);
 
-        _tfTopLeft = new () { Id = "_tfTopLeft", Width = width, Text = text };
-        appWindow.Add (_tfTopLeft);
+            var text = "Context Menu";
+            var width = 20;
+
+            CreateWinContextMenu (ApplicationImpl.Instance);
 
-        _tfTopRight = new () { Id = "_tfTopRight", X = Pos.AnchorEnd (width), Width = width, Text = text };
-        appWindow.Add (_tfTopRight);
+            var label = new Label
+            {
+                X = Pos.Center (), Y = 1, Text = $"Press '{_winContextMenuKey}' to open the Window context menu."
+            };
+            _appWindow.Add (label);
 
-        _tfMiddle = new () { Id = "_tfMiddle", X = Pos.Center (), Y = Pos.Center (), Width = width, Text = text };
-        appWindow.Add (_tfMiddle);
+            label = new ()
+            {
+                X = Pos.Center (),
+                Y = Pos.Bottom (label),
+                Text = $"Press '{PopoverMenu.DefaultKey}' to open the TextField context menu."
+            };
+            _appWindow.Add (label);
 
-        _tfBottomLeft = new () { Id = "_tfBottomLeft", Y = Pos.AnchorEnd (1), Width = width, Text = text };
-        appWindow.Add (_tfBottomLeft);
+            _tfTopLeft = new () { Id = "_tfTopLeft", Width = width, Text = text };
+            _appWindow.Add (_tfTopLeft);
 
-        _tfBottomRight = new () { Id = "_tfBottomRight", X = Pos.AnchorEnd (width), Y = Pos.AnchorEnd (1), Width = width, Text = text };
-        appWindow.Add (_tfBottomRight);
+            _tfTopRight = new () { Id = "_tfTopRight", X = Pos.AnchorEnd (width), Width = width, Text = text };
+            _appWindow.Add (_tfTopRight);
 
-        appWindow.KeyDown += OnAppWindowOnKeyDown;
-        appWindow.MouseClick += OnAppWindowOnMouseClick;
+            _tfMiddle = new () { Id = "_tfMiddle", X = Pos.Center (), Y = Pos.Center (), Width = width, Text = text };
+            _appWindow.Add (_tfMiddle);
 
-        CultureInfo originalCulture = Thread.CurrentThread.CurrentUICulture;
-        appWindow.Closed += (s, e) => { Thread.CurrentThread.CurrentUICulture = originalCulture; };
+            _tfBottomLeft = new () { Id = "_tfBottomLeft", Y = Pos.AnchorEnd (1), Width = width, Text = text };
+            _appWindow.Add (_tfBottomLeft);
 
-        // Run - Start the application.
-        Application.Run (appWindow);
-        appWindow.Dispose ();
-        appWindow.KeyDown -= OnAppWindowOnKeyDown;
-        appWindow.MouseClick -= OnAppWindowOnMouseClick;
-        _winContextMenu?.Dispose ();
+            _tfBottomRight = new () { Id = "_tfBottomRight", X = Pos.AnchorEnd (width), Y = Pos.AnchorEnd (1), Width = width, Text = text };
+            _appWindow.Add (_tfBottomRight);
 
-        // Shutdown - Calling Application.Shutdown is required.
-        Application.Shutdown ();
+            _appWindow.KeyDown += OnAppWindowOnKeyDown;
+            _appWindow.MouseClick += OnAppWindowOnMouseClick;
 
-        return;
+            CultureInfo originalCulture = Thread.CurrentThread.CurrentUICulture;
+            _appWindow.IsRunningChanged += (s, e) => {
+                                               if (!e.Value)
+                                               {
+                                                   Thread.CurrentThread.CurrentUICulture = originalCulture;
+                                               } };
+        }
 
-        void OnAppWindowOnMouseClick (object s, MouseEventArgs e)
+        void OnAppWindowOnMouseClick (object? s, MouseEventArgs e)
         {
             if (e.Flags == MouseFlags.Button3Clicked)
             {
@@ -88,7 +101,7 @@ public class ContextMenus : Scenario
             }
         }
 
-        void OnAppWindowOnKeyDown (object s, Key e)
+        void OnAppWindowOnKeyDown (object? s, Key e)
         {
             if (e == _winContextMenuKey)
             {
@@ -99,27 +112,21 @@ public class ContextMenus : Scenario
         }
     }
 
-    private void CreateWinContextMenu ()
+    private void CreateWinContextMenu (IApplication? app)
     {
-        if (_winContextMenu is { })
-        {
-            _winContextMenu.Dispose ();
-            _winContextMenu = null;
-        }
-
         _winContextMenu = new (
                                [
-                                   new MenuItemv2
+                                   new MenuItem
                                    {
                                        Title = "C_ultures",
                                        SubMenu = GetSupportedCultureMenu (),
                                    },
                                    new Line (),
-                                   new MenuItemv2
+                                   new MenuItem
                                    {
                                        Title = "_Configuration...",
                                        HelpText = "Show configuration",
-                                       Action = () => MessageBox.Query (
+                                       Action = () => MessageBox.Query (app,
                                                                         50,
                                                                         10,
                                                                         "Configuration",
@@ -127,17 +134,17 @@ public class ContextMenus : Scenario
                                                                         "Ok"
                                                                        )
                                    },
-                                   new MenuItemv2
+                                   new MenuItem
                                    {
                                        Title = "M_ore options",
                                        SubMenu = new (
                                                       [
-                                                          new MenuItemv2
+                                                          new MenuItem
                                                           {
                                                               Title = "_Setup...",
                                                               HelpText = "Perform setup",
                                                               Action = () => MessageBox
-                                                                           .Query (
+                                                                           .Query (app,
                                                                                    50,
                                                                                    10,
                                                                                    "Setup",
@@ -146,12 +153,12 @@ public class ContextMenus : Scenario
                                                                                   ),
                                                               Key = Key.T.WithCtrl
                                                           },
-                                                          new MenuItemv2
+                                                          new MenuItem
                                                           {
                                                               Title = "_Maintenance...",
                                                               HelpText = "Maintenance mode",
                                                               Action = () => MessageBox
-                                                                           .Query (
+                                                                           .Query (app,
                                                                                    50,
                                                                                    10,
                                                                                    "Maintenance",
@@ -162,7 +169,7 @@ public class ContextMenus : Scenario
                                                       ])
                                    },
                                    new Line (),
-                                   new MenuItemv2
+                                   new MenuItem
                                    {
                                        Title = "_Quit",
                                        Action = () => Application.RequestStop ()
@@ -171,16 +178,17 @@ public class ContextMenus : Scenario
         {
             Key = _winContextMenuKey
         };
+        Application.Popover?.Register (_winContextMenu);
     }
 
-    private Menuv2 GetSupportedCultureMenu ()
+    private Menu GetSupportedCultureMenu ()
     {
-        List<MenuItemv2> supportedCultures = [];
+        List<MenuItem> supportedCultures = [];
         int index = -1;
 
-        foreach (CultureInfo c in _cultureInfos)
+        foreach (CultureInfo c in _cultureInfos!)
         {
-            MenuItemv2 culture = new ();
+            MenuItem culture = new ();
 
             culture.CommandView = new CheckBox { CanFocus = false };
 
@@ -211,17 +219,17 @@ public class ContextMenus : Scenario
             supportedCultures.Add (culture);
         }
 
-        Menuv2 menu = new (supportedCultures.ToArray ());
+        Menu menu = new (supportedCultures.ToArray ());
 
         return menu;
 
-        void CreateAction (List<MenuItemv2> cultures, MenuItemv2 culture)
+        void CreateAction (List<MenuItem> cultures, MenuItem culture)
         {
             culture.Action += () =>
                               {
                                   Thread.CurrentThread.CurrentUICulture = new (culture.HelpText);
 
-                                  foreach (MenuItemv2 item in cultures)
+                                  foreach (MenuItem item in cultures)
                                   {
                                       ((CheckBox)item.CommandView).CheckedState =
                                           Thread.CurrentThread.CurrentUICulture.Name == item.HelpText ? CheckState.Checked : CheckState.UnChecked;

+ 270 - 211
Examples/UICatalog/Scenarios/CsvEditor.cs

@@ -1,8 +1,7 @@
-using System;
+#nullable enable
+
 using System.Data;
 using System.Globalization;
-using System.IO;
-using System.Linq;
 using System.Text.RegularExpressions;
 using CsvHelper;
 
@@ -14,99 +13,37 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Controls")]
 [ScenarioCategory ("Dialogs")]
 [ScenarioCategory ("Text and Formatting")]
-[ScenarioCategory ("Dialogs")]
 [ScenarioCategory ("Arrangement")]
 [ScenarioCategory ("Files and IO")]
 public class CsvEditor : Scenario
 {
-    private string _currentFile;
-    private DataTable _currentTable;
-    private MenuItem _miCentered;
-    private MenuItem _miLeft;
-    private MenuItem _miRight;
-    private TextField _selectedCellTextField;
-    private TableView _tableView;
+    private string? _currentFile;
+    private DataTable? _currentTable;
+    private CheckBox? _miCenteredCheckBox;
+    private CheckBox? _miLeftCheckBox;
+    private CheckBox? _miRightCheckBox;
+    private TextField? _selectedCellTextField;
+    private TableView? _tableView;
 
     public override void Main ()
     {
-        // Init
         Application.Init ();
 
-        // Setup - Create a top-level application window and configure it.
-        Toplevel appWindow = new ()
+        Window appWindow = new ()
         {
-            Title = $"{GetName ()}"
+            Title = GetName ()
         };
 
-        //appWindow.Height = Dim.Fill (1); // status bar
-
-        _tableView = new () { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill (2) };
+        // MenuBar
+        MenuBar menu = new ();
 
-        var fileMenu = new MenuBarItem (
-                                        "_File",
-                                        new MenuItem []
-                                        {
-                                            new ("_Open CSV", "", () => Open ()),
-                                            new ("_Save", "", () => Save ()),
-                                            new ("_Quit", "Quits The App", () => Quit ())
-                                        }
-                                       );
-
-        //fileMenu.Help = "Help";
-        var menu = new MenuBar
-        {
-            Menus =
-            [
-                fileMenu,
-                new (
-                     "_Edit",
-                     new MenuItem []
-                     {
-                         new ("_New Column", "", () => AddColumn ()),
-                         new ("_New Row", "", () => AddRow ()),
-                         new (
-                              "_Rename Column",
-                              "",
-                              () => RenameColumn ()
-                             ),
-                         new ("_Delete Column", "", () => DeleteColum ()),
-                         new ("_Move Column", "", () => MoveColumn ()),
-                         new ("_Move Row", "", () => MoveRow ()),
-                         new ("_Sort Asc", "", () => Sort (true)),
-                         new ("_Sort Desc", "", () => Sort (false))
-                     }
-                    ),
-                new (
-                     "_View",
-                     new []
-                     {
-                         _miLeft = new (
-                                        "_Align Left",
-                                        "",
-                                        () => Align (Alignment.Start)
-                                       ),
-                         _miRight = new (
-                                         "_Align Right",
-                                         "",
-                                         () => Align (Alignment.End)
-                                        ),
-                         _miCentered = new (
-                                            "_Align Centered",
-                                            "",
-                                            () => Align (Alignment.Center)
-                                           ),
-
-                         // Format requires hard typed data table, when we read a CSV everything is untyped (string) so this only works for new columns in this demo
-                         _miCentered = new (
-                                            "_Set Format Pattern",
-                                            "",
-                                            () => SetFormat ()
-                                           )
-                     }
-                    )
-            ]
+        _tableView = new ()
+        {
+            X = 0,
+            Y = Pos.Bottom (menu),
+            Width = Dim.Fill (),
+            Height = Dim.Fill (1)
         };
-        appWindow.Add (menu);
 
         _selectedCellTextField = new ()
         {
@@ -116,57 +53,169 @@ public class CsvEditor : Scenario
         };
         _selectedCellTextField.TextChanged += SelectedCellLabel_TextChanged;
 
-        var statusBar = new StatusBar (
-                                       [
-                                           new (Application.QuitKey, "Quit", Quit, "Quit!"),
-                                           new (Key.O.WithCtrl, "Open", Open, "Open a file."),
-                                           new (Key.S.WithCtrl, "Save", Save, "Save current."),
-                                           new ()
-                                           {
-                                               HelpText = "Cell:",
-                                               CommandView = _selectedCellTextField,
-                                               AlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.IgnoreFirstOrLast,
-                                               Enabled = false
-                                           }
-                                       ])
+        // StatusBar
+        StatusBar statusBar = new (
+                                   [
+                                       new (Application.QuitKey, "Quit", Quit, "Quit!"),
+                                       new (Key.O.WithCtrl, "Open", Open, "Open a file."),
+                                       new (Key.S.WithCtrl, "Save", Save, "Save current."),
+                                       new ()
+                                       {
+                                           HelpText = "Cell:",
+                                           CommandView = _selectedCellTextField,
+                                           AlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.IgnoreFirstOrLast,
+                                           Enabled = false
+                                       }
+                                   ]
+                                  )
         {
             AlignmentModes = AlignmentModes.IgnoreFirstOrLast
         };
-        appWindow.Add (statusBar);
 
-        appWindow.Add (_tableView);
+        // Setup menu checkboxes for alignment
+        _miLeftCheckBox = new ()
+        {
+            Title = "_Align Left"
+        };
+        _miLeftCheckBox.CheckedStateChanged += (s, e) => Align (Alignment.Start);
+
+        _miRightCheckBox = new ()
+        {
+            Title = "_Align Right"
+        };
+        _miRightCheckBox.CheckedStateChanged += (s, e) => Align (Alignment.End);
+
+        _miCenteredCheckBox = new ()
+        {
+            Title = "_Align Centered"
+        };
+        _miCenteredCheckBox.CheckedStateChanged += (s, e) => Align (Alignment.Center);
+
+        MenuBarItem fileMenu = new (
+                                    "_File",
+                                    [
+                                        new MenuItem
+                                        {
+                                            Title = "_Open CSV",
+                                            Action = Open
+                                        },
+                                        new MenuItem
+                                        {
+                                            Title = "_Save",
+                                            Action = Save
+                                        },
+                                        new MenuItem
+                                        {
+                                            Title = "_Quit",
+                                            HelpText = "Quits The App",
+                                            Action = Quit
+                                        }
+                                    ]
+                                   );
+
+        menu.Add (fileMenu);
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_Edit",
+                                   [
+                                       new MenuItem
+                                       {
+                                           Title = "_New Column",
+                                           Action = AddColumn
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_New Row",
+                                           Action = AddRow
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Rename Column",
+                                           Action = RenameColumn
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Delete Column",
+                                           Action = DeleteColum
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Move Column",
+                                           Action = MoveColumn
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Move Row",
+                                           Action = MoveRow
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Sort Asc",
+                                           Action = () => Sort (true)
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Sort Desc",
+                                           Action = () => Sort (false)
+                                       }
+                                   ]
+                                  )
+                 );
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_View",
+                                   [
+                                       new MenuItem
+                                       {
+                                           CommandView = _miLeftCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _miRightCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _miCenteredCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Set Format Pattern",
+                                           Action = SetFormat
+                                       }
+                                   ]
+                                  )
+                 );
+
+        appWindow.Add (menu, _tableView, statusBar);
 
         _tableView.SelectedCellChanged += OnSelectedCellChanged;
         _tableView.CellActivated += EditCurrentCell;
         _tableView.KeyDown += TableViewKeyPress;
 
-        //SetupScrollBar ();
-
-        // Run - Start the application.
         Application.Run (appWindow);
         appWindow.Dispose ();
-
-        // Shutdown - Calling Application.Shutdown is required.
         Application.Shutdown ();
     }
 
     private void AddColumn ()
     {
-        if (NoTableLoaded ())
+        if (NoTableLoaded () || _tableView is null || _currentTable is null)
         {
             return;
         }
 
         if (GetText ("Enter column name", "Name:", "", out string colName))
         {
-            var col = new DataColumn (colName);
+            DataColumn col = new (colName);
 
             int newColIdx = Math.Min (
                                       Math.Max (0, _tableView.SelectedColumn + 1),
                                       _tableView.Table.Columns
                                      );
 
-            int result = MessageBox.Query (
+            int? result = MessageBox.Query (ApplicationImpl.Instance,
                                            "Column Type",
                                            "Pick a data type for the column",
                                            "Date",
@@ -176,7 +225,7 @@ public class CsvEditor : Scenario
                                            "Cancel"
                                           );
 
-            if (result <= -1 || result >= 4)
+            if (result is null || result >= 4)
             {
                 return;
             }
@@ -209,7 +258,7 @@ public class CsvEditor : Scenario
 
     private void AddRow ()
     {
-        if (NoTableLoaded ())
+        if (NoTableLoaded () || _currentTable is null || _tableView is null)
         {
             return;
         }
@@ -224,7 +273,7 @@ public class CsvEditor : Scenario
 
     private void Align (Alignment newAlignment)
     {
-        if (NoTableLoaded ())
+        if (NoTableLoaded () || _tableView is null)
         {
             return;
         }
@@ -232,31 +281,34 @@ public class CsvEditor : Scenario
         ColumnStyle style = _tableView.Style.GetOrCreateColumnStyle (_tableView.SelectedColumn);
         style.Alignment = newAlignment;
 
-        _miLeft.Checked = style.Alignment == Alignment.Start;
-        _miRight.Checked = style.Alignment == Alignment.End;
-        _miCentered.Checked = style.Alignment == Alignment.Center;
+        if (_miLeftCheckBox is { })
+        {
+            _miLeftCheckBox.CheckedState = style.Alignment == Alignment.Start ? CheckState.Checked : CheckState.UnChecked;
+        }
 
-        _tableView.Update ();
-    }
+        if (_miRightCheckBox is { })
+        {
+            _miRightCheckBox.CheckedState = style.Alignment == Alignment.End ? CheckState.Checked : CheckState.UnChecked;
+        }
+
+        if (_miCenteredCheckBox is { })
+        {
+            _miCenteredCheckBox.CheckedState = style.Alignment == Alignment.Center ? CheckState.Checked : CheckState.UnChecked;
+        }
 
-    private void ClearColumnStyles ()
-    {
-        _tableView.Style.ColumnStyles.Clear ();
         _tableView.Update ();
     }
 
-    private void CloseExample () { _tableView.Table = null; }
-
     private void DeleteColum ()
     {
-        if (NoTableLoaded ())
+        if (NoTableLoaded () || _tableView is null || _currentTable is null)
         {
             return;
         }
 
         if (_tableView.SelectedColumn == -1)
         {
-            MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
 
             return;
         }
@@ -268,20 +320,20 @@ public class CsvEditor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery ("Could not remove column", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Could not remove column", ex.Message, "Ok");
         }
     }
 
-    private void EditCurrentCell (object sender, CellActivatedEventArgs e)
+    private void EditCurrentCell (object? sender, CellActivatedEventArgs e)
     {
-        if (e.Table == null)
+        if (e.Table is null || _currentTable is null || _tableView is null)
         {
             return;
         }
 
         var oldValue = _currentTable.Rows [e.Row] [e.Col].ToString ();
 
-        if (GetText ("Enter new value", _currentTable.Columns [e.Col].ColumnName, oldValue, out string newText))
+        if (GetText ("Enter new value", _currentTable.Columns [e.Col].ColumnName, oldValue ?? "", out string newText))
         {
             try
             {
@@ -290,7 +342,7 @@ public class CsvEditor : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (60, 20, "Failed to set text", ex.Message, "Ok");
+                MessageBox.ErrorQuery (ApplicationImpl.Instance, 60, 20, "Failed to set text", ex.Message, "Ok");
             }
 
             _tableView.Update ();
@@ -301,20 +353,20 @@ public class CsvEditor : Scenario
     {
         var okPressed = false;
 
-        var ok = new Button { Text = "Ok", IsDefault = true };
+        Button ok = new () { Text = "Ok", IsDefault = true };
 
         ok.Accepting += (s, e) =>
-                     {
-                         okPressed = true;
-                         Application.RequestStop ();
-                     };
-        var cancel = new Button { Text = "Cancel" };
+                        {
+                            okPressed = true;
+                            Application.RequestStop ();
+                        };
+        Button cancel = new () { Text = "Cancel" };
         cancel.Accepting += (s, e) => { Application.RequestStop (); };
-        var d = new Dialog { Title = title, Buttons = [ok, cancel] };
+        Dialog d = new () { Title = title, Buttons = [ok, cancel] };
 
-        var lbl = new Label { X = 0, Y = 1, Text = label };
+        Label lbl = new () { X = 0, Y = 1, Text = label };
 
-        var tf = new TextField { Text = initialText, X = 0, Y = 2, Width = Dim.Fill () };
+        TextField tf = new () { Text = initialText, X = 0, Y = 2, Width = Dim.Fill () };
 
         d.Add (lbl, tf);
         tf.SetFocus ();
@@ -322,21 +374,21 @@ public class CsvEditor : Scenario
         Application.Run (d);
         d.Dispose ();
 
-        enteredText = okPressed ? tf.Text : null;
+        enteredText = okPressed ? tf.Text : string.Empty;
 
         return okPressed;
     }
 
     private void MoveColumn ()
     {
-        if (NoTableLoaded ())
+        if (NoTableLoaded () || _currentTable is null || _tableView is null)
         {
             return;
         }
 
         if (_tableView.SelectedColumn == -1)
         {
-            MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
 
             return;
         }
@@ -361,20 +413,20 @@ public class CsvEditor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery ("Error moving column", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error moving column", ex.Message, "Ok");
         }
     }
 
     private void MoveRow ()
     {
-        if (NoTableLoaded ())
+        if (NoTableLoaded () || _currentTable is null || _tableView is null)
         {
             return;
         }
 
         if (_tableView.SelectedRow == -1)
         {
-            MessageBox.ErrorQuery ("No Rows", "No row selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Rows", "No row selected", "Ok");
 
             return;
         }
@@ -394,7 +446,7 @@ public class CsvEditor : Scenario
                     return;
                 }
 
-                object [] arrayItems = currentRow.ItemArray;
+                object? [] arrayItems = currentRow.ItemArray;
                 _currentTable.Rows.Remove (currentRow);
 
                 // Removing and Inserting the same DataRow seems to result in it loosing its values so we have to create a new instance
@@ -410,15 +462,15 @@ public class CsvEditor : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery ("Error moving column", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error moving column", ex.Message, "Ok");
         }
     }
 
     private bool NoTableLoaded ()
     {
-        if (_tableView.Table == null)
+        if (_tableView?.Table is null)
         {
-            MessageBox.ErrorQuery ("No Table Loaded", "No table has currently be opened", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Table Loaded", "No table has currently be opened", "Ok");
 
             return true;
         }
@@ -426,31 +478,47 @@ public class CsvEditor : Scenario
         return false;
     }
 
-    private void OnSelectedCellChanged (object sender, SelectedCellChangedEventArgs e)
+    private void OnSelectedCellChanged (object? sender, SelectedCellChangedEventArgs e)
     {
+        if (_selectedCellTextField is null || _tableView is null)
+        {
+            return;
+        }
+
         // only update the text box if the user is not manually editing it
         if (!_selectedCellTextField.HasFocus)
         {
             _selectedCellTextField.Text = $"{_tableView.SelectedRow},{_tableView.SelectedColumn}";
         }
 
-        if (_tableView.Table == null || _tableView.SelectedColumn == -1)
+        if (_tableView.Table is null || _tableView.SelectedColumn == -1)
         {
             return;
         }
 
-        ColumnStyle style = _tableView.Style.GetColumnStyleIfAny (_tableView.SelectedColumn);
+        ColumnStyle? style = _tableView.Style.GetColumnStyleIfAny (_tableView.SelectedColumn);
+
+        if (_miLeftCheckBox is { })
+        {
+            _miLeftCheckBox.CheckedState = style?.Alignment == Alignment.Start ? CheckState.Checked : CheckState.UnChecked;
+        }
+
+        if (_miRightCheckBox is { })
+        {
+            _miRightCheckBox.CheckedState = style?.Alignment == Alignment.End ? CheckState.Checked : CheckState.UnChecked;
+        }
 
-        _miLeft.Checked = style?.Alignment == Alignment.Start;
-        _miRight.Checked = style?.Alignment == Alignment.End;
-        _miCentered.Checked = style?.Alignment == Alignment.Center;
+        if (_miCenteredCheckBox is { })
+        {
+            _miCenteredCheckBox.CheckedState = style?.Alignment == Alignment.Center ? CheckState.Checked : CheckState.UnChecked;
+        }
     }
 
     private void Open ()
     {
-        var ofd = new FileDialog
+        FileDialog ofd = new ()
         {
-            AllowedTypes = new () { new AllowedType ("Comma Separated Values", ".csv") }
+            AllowedTypes = [new AllowedType ("Comma Separated Values", ".csv")]
         };
         ofd.Style.OkButtonText = "Open";
 
@@ -471,13 +539,13 @@ public class CsvEditor : Scenario
 
         try
         {
-            using var reader = new CsvReader (File.OpenText (filename), CultureInfo.InvariantCulture);
+            using CsvReader reader = new (File.OpenText (filename), CultureInfo.InvariantCulture);
 
-            var dt = new DataTable ();
+            DataTable dt = new ();
 
             reader.Read ();
 
-            if (reader.ReadHeader ())
+            if (reader.ReadHeader () && reader.HeaderRecord is { })
             {
                 foreach (string h in reader.HeaderRecord)
                 {
@@ -501,12 +569,20 @@ public class CsvEditor : Scenario
 
             // Only set the current filename if we successfully loaded the entire file
             _currentFile = filename;
-            _selectedCellTextField.SuperView.Enabled = true;
-            Application.Top.Title = $"{GetName ()} - {Path.GetFileName (_currentFile)}";
+
+            if (_selectedCellTextField?.SuperView is { })
+            {
+                _selectedCellTextField.SuperView.Enabled = true;
+            }
+
+            if (Application.TopRunnableView is { })
+            {
+                Application.TopRunnableView.Title = $"{GetName ()} - {Path.GetFileName (_currentFile)}";
+            }
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery (
+            MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                    "Open Failed",
                                    $"Error on line {lineNumber}{Environment.NewLine}{ex.Message}",
                                    "Ok"
@@ -518,7 +594,7 @@ public class CsvEditor : Scenario
 
     private void RenameColumn ()
     {
-        if (NoTableLoaded ())
+        if (NoTableLoaded () || _currentTable is null || _tableView is null)
         {
             return;
         }
@@ -534,17 +610,17 @@ public class CsvEditor : Scenario
 
     private void Save ()
     {
-        if (_tableView.Table == null || string.IsNullOrWhiteSpace (_currentFile))
+        if (_tableView?.Table is null || string.IsNullOrWhiteSpace (_currentFile) || _currentTable is null)
         {
-            MessageBox.ErrorQuery ("No file loaded", "No file is currently loaded", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No file loaded", "No file is currently loaded", "Ok");
 
             return;
         }
 
-        using var writer = new CsvWriter (
-                                          new StreamWriter (File.OpenWrite (_currentFile)),
-                                          CultureInfo.InvariantCulture
-                                         );
+        using CsvWriter writer = new (
+                                      new StreamWriter (File.OpenWrite (_currentFile)),
+                                      CultureInfo.InvariantCulture
+                                     );
 
         foreach (string col in _currentTable.Columns.Cast<DataColumn> ().Select (c => c.ColumnName))
         {
@@ -555,7 +631,7 @@ public class CsvEditor : Scenario
 
         foreach (DataRow row in _currentTable.Rows)
         {
-            foreach (object item in row.ItemArray)
+            foreach (object? item in row.ItemArray)
             {
                 writer.WriteField (item);
             }
@@ -564,8 +640,13 @@ public class CsvEditor : Scenario
         }
     }
 
-    private void SelectedCellLabel_TextChanged (object sender, EventArgs e)
+    private void SelectedCellLabel_TextChanged (object? sender, EventArgs e)
     {
+        if (_selectedCellTextField is null || _tableView is null)
+        {
+            return;
+        }
+
         // if user is in the text control and editing the selected cell
         if (!_selectedCellTextField.HasFocus)
         {
@@ -577,14 +658,14 @@ public class CsvEditor : Scenario
 
         if (match.Success)
         {
-            _tableView.SelectedColumn = int.Parse (match.Groups [1].Value);
-            _tableView.SelectedRow = int.Parse (match.Groups [2].Value);
+            _tableView.SelectedColumn = int.Parse (match.Groups [2].Value);
+            _tableView.SelectedRow = int.Parse (match.Groups [1].Value);
         }
     }
 
     private void SetFormat ()
     {
-        if (NoTableLoaded ())
+        if (NoTableLoaded () || _currentTable is null || _tableView is null)
         {
             return;
         }
@@ -593,7 +674,7 @@ public class CsvEditor : Scenario
 
         if (col.DataType == typeof (string))
         {
-            MessageBox.ErrorQuery (
+            MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                    "Cannot Format Column",
                                    "String columns cannot be Formatted, try adding a new column to the table with a date/numerical Type",
                                    "Ok"
@@ -611,53 +692,26 @@ public class CsvEditor : Scenario
         }
     }
 
-    private void SetTable (DataTable dataTable) { _tableView.Table = new DataTableSource (_currentTable = dataTable); }
-
-    //private void SetupScrollBar ()
-    //{
-    //    var scrollBar = new ScrollBarView (_tableView, true);
-
-    //    scrollBar.ChangedPosition += (s, e) =>
-    //                                 {
-    //                                     _tableView.RowOffset = scrollBar.Position;
-
-    //                                     if (_tableView.RowOffset != scrollBar.Position)
-    //                                     {
-    //                                         scrollBar.Position = _tableView.RowOffset;
-    //                                     }
-
-    //                                     _tableView.SetNeedsDraw ();
-    //                                 };
-    //    /*
-    //    scrollBar.OtherScrollBarView.ChangedPosition += (s,e) => {
-    //        tableView.LeftItem = scrollBar.OtherScrollBarView.Position;
-    //        if (tableView.LeftItem != scrollBar.OtherScrollBarView.Position) {
-    //            scrollBar.OtherScrollBarView.Position = tableView.LeftItem;
-    //        }
-    //        tableView.SetNeedsDraw ();
-    //    };*/
-
-    //    _tableView.DrawingContent += (s, e) =>
-    //                              {
-    //                                  scrollBar.Size = _tableView.Table?.Rows ?? 0;
-    //                                  scrollBar.Position = _tableView.RowOffset;
-
-    //                                  //scrollBar.OtherScrollBarView.Size = tableView.Maxlength - 1;
-    //                                  //scrollBar.OtherScrollBarView.Position = tableView.LeftItem;
-    //                                  scrollBar.Refresh ();
-    //                              };
-    //}
+    private void SetTable (DataTable dataTable)
+    {
+        if (_tableView is null)
+        {
+            return;
+        }
+
+        _tableView.Table = new DataTableSource (_currentTable = dataTable);
+    }
 
     private void Sort (bool asc)
     {
-        if (NoTableLoaded ())
+        if (NoTableLoaded () || _currentTable is null || _tableView is null)
         {
             return;
         }
 
         if (_tableView.SelectedColumn == -1)
         {
-            MessageBox.ErrorQuery ("No Column", "No column selected", "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "No Column", "No column selected", "Ok");
 
             return;
         }
@@ -668,9 +722,14 @@ public class CsvEditor : Scenario
         SetTable (_currentTable.DefaultView.ToTable ());
     }
 
-    private void TableViewKeyPress (object sender, Key e)
+    private void TableViewKeyPress (object? sender, Key e)
     {
-        if (e.KeyCode == KeyCode.Delete)
+        if (_currentTable is null || _tableView is null)
+        {
+            return;
+        }
+
+        if (e.KeyCode == Key.Delete)
         {
             if (_tableView.FullRowSelect)
             {

+ 14 - 11
Examples/UICatalog/Scenarios/Dialogs.cs

@@ -151,18 +151,15 @@ public class Dialogs : Scenario
         };
         frame.Add (label);
 
-        // Add hotkeys
-        var labels = Enum.GetNames<Alignment> ().Select (n => n = "_" + n);
-        var alignmentGroup = new RadioGroup
+        OptionSelector<Alignment> alignmentOptionSelector = new ()
         {
             X = Pos.Right (label) + 1,
             Y = Pos.Top (label),
-            RadioLabels = labels.ToArray (),
             Title = "Ali_gn",
-            BorderStyle = LineStyle.Dashed
+            AssignHotKeys = true
         };
-        frame.Add (alignmentGroup);
-        alignmentGroup.SelectedItem = labels.ToList ().IndexOf ("_" + Dialog.DefaultButtonAlignment.ToString ());
+        frame.Add (alignmentOptionSelector);
+        alignmentOptionSelector.Value = Dialog.DefaultButtonAlignment;
 
         frame.ValidatePosDim = true;
 
@@ -192,7 +189,7 @@ public class Dialogs : Scenario
                                                                       titleEdit,
                                                                       numButtonsEdit,
                                                                       glyphsNotWords,
-                                                                      alignmentGroup,
+                                                                      alignmentOptionSelector,
                                                                       buttonPressedLabel
                                                                      );
                                        Application.Run (dlg);
@@ -216,7 +213,7 @@ public class Dialogs : Scenario
         TextField titleEdit,
         TextField numButtonsEdit,
         CheckBox glyphsNotWords,
-        RadioGroup alignmentRadioGroup,
+        OptionSelector alignmentGroup,
         Label buttonPressedLabel
     )
     {
@@ -269,7 +266,7 @@ public class Dialogs : Scenario
             {
                 Title = titleEdit.Text,
                 Text = "Dialog Text",
-                ButtonAlignment = (Alignment)Enum.Parse (typeof (Alignment), alignmentRadioGroup.RadioLabels [alignmentRadioGroup.SelectedItem].Substring (1)),
+                ButtonAlignment = (Alignment)Enum.Parse (typeof (Alignment), alignmentGroup.Labels! [(int)alignmentGroup.Value!.Value] [0..]),
 
                 Buttons = buttons.ToArray ()
             };
@@ -343,7 +340,13 @@ public class Dialogs : Scenario
                               };
             dialog.Add (addChar);
 
-            dialog.Closed += (s, e) => { buttonPressedLabel.Text = $"{clicked}"; };
+            dialog.IsRunningChanged += (s, e) =>
+                                       {
+                                           if (!e.Value)
+                                           {
+                                               buttonPressedLabel.Text = $"{clicked}";
+                                           }
+                                       };
         }
         catch (FormatException)
         {

+ 5 - 5
Examples/UICatalog/Scenarios/DimAutoDemo.cs

@@ -56,7 +56,7 @@ public class DimAutoDemo : Scenario
             Width = Dim.Auto (DimAutoStyle.Content, minimumContentDim: Dim.Percent (25)),
             Height = Dim.Auto (DimAutoStyle.Content, minimumContentDim: 10)
         };
-        dimAutoFrameView.Margin.Thickness = new Thickness (1);
+        dimAutoFrameView.Margin!.Thickness = new Thickness (1);
         dimAutoFrameView.ValidatePosDim = true;
 
         var textEdit = new TextView
@@ -163,15 +163,15 @@ public class DimAutoDemo : Scenario
         dimAutoFrameView.Add (resetButton);
 
 
-        var radioGroup = new RadioGroup ()
+        var optionSelector = new OptionSelector ()
         {
-            RadioLabels = ["One", "Two", "Three"],
+            Labels = ["One", "Two", "Three"],
             X = 0,
             Y = Pos.AnchorEnd (),
-            Title = "Radios",
+            Title = "Options",
             BorderStyle = LineStyle.Dotted
         };
-        dimAutoFrameView.Add (radioGroup);
+        dimAutoFrameView.Add (optionSelector);
         return dimAutoFrameView;
     }
 

+ 0 - 1413
Examples/UICatalog/Scenarios/DynamicMenuBar.cs

@@ -1,1413 +0,0 @@
-using System.Collections.ObjectModel;
-using System.ComponentModel;
-using System.Reflection;
-using System.Runtime.CompilerServices;
-using System.Text;
-
-#pragma warning disable CS0618 // Type or member is obsolete
-
-namespace UICatalog.Scenarios;
-
-[ScenarioMetadata ("Dynamic MenuBar", "Demonstrates how to change a MenuBar dynamically.")]
-[ScenarioCategory ("Arrangement")]
-[ScenarioCategory ("Menus")]
-public class DynamicMenuBar : Scenario
-{
-    public override void Main ()
-    {
-        // Init
-        Application.Init ();
-
-        // Setup - Create a top-level application window and configure it.
-        DynamicMenuBarSample appWindow = new ()
-        {
-            Title = GetQuitKeyAndName ()
-        };
-
-        // Run - Start the application.
-        Application.Run (appWindow);
-        appWindow.Dispose ();
-
-        // Shutdown - Calling Application.Shutdown is required.
-        Application.Shutdown ();
-    }
-
-    public class Binding
-    {
-        private readonly PropertyInfo _sourceBindingProperty;
-        private readonly object _sourceDataContext;
-        private readonly IValueConverter _valueConverter;
-
-        public Binding (
-            View source,
-            string sourcePropertyName,
-            View target,
-            string targetPropertyName,
-            IValueConverter valueConverter = null
-        )
-        {
-            Target = target;
-            Source = source;
-            SourcePropertyName = sourcePropertyName;
-            TargetPropertyName = targetPropertyName;
-            _sourceDataContext = Source.GetType ().GetProperty ("DataContext").GetValue (Source);
-            _sourceBindingProperty = _sourceDataContext.GetType ().GetProperty (SourcePropertyName);
-            _valueConverter = valueConverter;
-            UpdateTarget ();
-
-            var notifier = (INotifyPropertyChanged)_sourceDataContext;
-
-            if (notifier != null)
-            {
-                notifier.PropertyChanged += (s, e) =>
-                                            {
-                                                if (e.PropertyName == SourcePropertyName)
-                                                {
-                                                    UpdateTarget ();
-                                                }
-                                            };
-            }
-        }
-
-        public View Source { get; }
-        public string SourcePropertyName { get; }
-        public View Target { get; }
-        public string TargetPropertyName { get; }
-
-        private void UpdateTarget ()
-        {
-            try
-            {
-                object sourceValue = _sourceBindingProperty.GetValue (_sourceDataContext);
-
-                if (sourceValue == null)
-                {
-                    return;
-                }
-
-                object finalValue = _valueConverter?.Convert (sourceValue) ?? sourceValue;
-
-                PropertyInfo targetProperty = Target.GetType ().GetProperty (TargetPropertyName);
-                targetProperty.SetValue (Target, finalValue);
-            }
-            catch (Exception ex)
-            {
-                MessageBox.ErrorQuery ("Binding Error", $"Binding failed: {ex}.", "Ok");
-            }
-        }
-    }
-
-    public class DynamicMenuBarDetails : FrameView
-    {
-        private bool _hasParent;
-        private MenuItem _menuItem;
-
-        public DynamicMenuBarDetails (MenuItem menuItem = null, bool hasParent = false) : this ()
-        {
-            _menuItem = menuItem;
-            _hasParent = hasParent;
-            Title = menuItem == null ? "Adding New Menu." : "Editing Menu.";
-        }
-
-        public DynamicMenuBarDetails ()
-        {
-            var lblTitle = new Label { Y = 1, Text = "Title:" };
-            Add (lblTitle);
-
-            TextTitle = new () { X = Pos.Right (lblTitle) + 2, Y = Pos.Top (lblTitle), Width = Dim.Fill () };
-            Add (TextTitle);
-
-            var lblHelp = new Label { X = Pos.Left (lblTitle), Y = Pos.Bottom (lblTitle) + 1, Text = "Help:" };
-            Add (lblHelp);
-
-            TextHelp = new () { X = Pos.Left (TextTitle), Y = Pos.Top (lblHelp), Width = Dim.Fill () };
-            Add (TextHelp);
-
-            var lblAction = new Label { X = Pos.Left (lblTitle), Y = Pos.Bottom (lblHelp) + 1, Text = "Action:" };
-            Add (lblAction);
-
-            TextAction = new ()
-            {
-                X = Pos.Left (TextTitle), Y = Pos.Top (lblAction), Width = Dim.Fill (), Height = 5
-            };
-            Add (TextAction);
-
-            var lblHotKey = new Label { X = Pos.Left (lblTitle), Y = Pos.Bottom (lblAction) + 5, Text = "HotKey:" };
-            Add (lblHotKey);
-
-            TextHotKey = new ()
-            {
-                X = Pos.Left (TextTitle), Y = Pos.Bottom (lblAction) + 5, Width = 2, ReadOnly = true
-            };
-
-            TextHotKey.TextChanging += (s, e) =>
-                                       {
-                                           if (!string.IsNullOrEmpty (e.Result) && char.IsLower (e.Result [0]))
-                                           {
-                                               e.Result = e.Result.ToUpper ();
-                                           }
-                                       };
-            TextHotKey.TextChanged += (s, _) => TextHotKey.SelectAll ();
-            TextHotKey.SelectAll ();
-            Add (TextHotKey);
-
-            CkbIsTopLevel = new ()
-            {
-                X = Pos.Left (lblTitle), Y = Pos.Bottom (lblHotKey) + 1, Text = "IsTopLevel"
-            };
-            Add (CkbIsTopLevel);
-
-            CkbSubMenu = new ()
-            {
-                X = Pos.Left (lblTitle),
-                Y = Pos.Bottom (CkbIsTopLevel),
-                CheckedState = (_menuItem == null ? !_hasParent : HasSubMenus (_menuItem)) ? CheckState.Checked : CheckState.UnChecked,
-                Text = "Has sub-menus"
-            };
-            Add (CkbSubMenu);
-
-            CkbNullCheck = new ()
-            {
-                X = Pos.Left (lblTitle), Y = Pos.Bottom (CkbSubMenu), Text = "Allow null checked"
-            };
-            Add (CkbNullCheck);
-
-            var rChkLabels = new [] { "NoCheck", "Checked", "Radio" };
-
-            RbChkStyle = new ()
-            {
-                X = Pos.Left (lblTitle), Y = Pos.Bottom (CkbSubMenu) + 1, RadioLabels = rChkLabels
-            };
-            Add (RbChkStyle);
-
-            var lblShortcut = new Label
-            {
-                X = Pos.Right (CkbSubMenu) + 10, Y = Pos.Top (CkbSubMenu), Text = "Shortcut:"
-            };
-            Add (lblShortcut);
-
-            TextShortcutKey = new ()
-            {
-                X = Pos.X (lblShortcut), Y = Pos.Bottom (lblShortcut), Width = Dim.Fill (), ReadOnly = true
-            };
-
-            TextShortcutKey.KeyDown += (s, e) =>
-                                    {
-                                        TextShortcutKey.Text = e.ToString ();
-
-                                    };
-
-            Add (TextShortcutKey);
-
-            var btnShortcut = new Button
-            {
-                X = Pos.X (lblShortcut), Y = Pos.Bottom (TextShortcutKey) + 1, Text = "Clear Shortcut"
-            };
-            btnShortcut.Accepting += (s, e) => { TextShortcutKey.Text = ""; };
-            Add (btnShortcut);
-
-            CkbIsTopLevel.CheckedStateChanging += (s, e) =>
-                                     {
-                                         if ((_menuItem != null && _menuItem.Parent != null && e.Result == CheckState.Checked)
-                                             || (_menuItem == null && _hasParent && e.Result == CheckState.Checked))
-                                         {
-                                             MessageBox.ErrorQuery (
-                                                                    "Invalid IsTopLevel",
-                                                                    "Only menu bar can have top level menu item!",
-                                                                    "Ok"
-                                                                   );
-                                             e.Handled = true;
-
-                                             return;
-                                         }
-
-                                         if (e.Result == CheckState.Checked)
-                                         {
-                                             CkbSubMenu.CheckedState = CheckState.UnChecked;
-                                             CkbSubMenu.SetNeedsDraw ();
-                                             TextHelp.Enabled = true;
-                                             TextAction.Enabled = true;
-                                             TextShortcutKey.Enabled = true;
-                                         }
-                                         else
-                                         {
-                                             if ((_menuItem == null && !_hasParent) || _menuItem.Parent == null)
-                                             {
-                                                 CkbSubMenu.CheckedState = CheckState.Checked;
-                                                 CkbSubMenu.SetNeedsDraw ();
-                                                 TextShortcutKey.Enabled = false;
-                                             }
-
-                                             TextHelp.Text = "";
-                                             TextHelp.Enabled = false;
-                                             TextAction.Text = "";
-
-                                             TextShortcutKey.Enabled =
-                                                 e.Result == CheckState.Checked && CkbSubMenu.CheckedState == CheckState.UnChecked;
-                                         }
-                                     };
-
-            CkbSubMenu.CheckedStateChanged += (s, e) =>
-                                  {
-                                      if (e.Value == CheckState.Checked)
-                                      {
-                                          CkbIsTopLevel.CheckedState = CheckState.UnChecked;
-                                          CkbIsTopLevel.SetNeedsDraw ();
-                                          TextHelp.Text = "";
-                                          TextHelp.Enabled = false;
-                                          TextAction.Text = "";
-                                          TextAction.Enabled = false;
-                                          TextShortcutKey.Text = "";
-                                          TextShortcutKey.Enabled = false;
-                                      }
-                                      else
-                                      {
-                                          if (!_hasParent)
-                                          {
-                                              CkbIsTopLevel.CheckedState = CheckState.Checked;
-                                              CkbIsTopLevel.SetNeedsDraw ();
-                                              TextShortcutKey.Enabled = true;
-                                          }
-
-                                          TextHelp.Enabled = true;
-                                          TextAction.Enabled = true;
-
-                                          if (_hasParent)
-                                          {
-                                              TextShortcutKey.Enabled = CkbIsTopLevel.CheckedState == CheckState.UnChecked
-                                                                     && e.Value == CheckState.UnChecked;
-                                          }
-                                      }
-                                  };
-
-            CkbNullCheck.CheckedStateChanged += (s, e) =>
-                                    {
-                                        if (_menuItem != null)
-                                        {
-                                            _menuItem.AllowNullChecked = e.Value == CheckState.Checked;
-                                        }
-                                    };
-
-            //Add (_frmMenuDetails);
-        }
-
-        public CheckBox CkbIsTopLevel { get; }
-        public CheckBox CkbNullCheck { get; }
-        public CheckBox CkbSubMenu { get; }
-        public RadioGroup RbChkStyle { get; }
-        public TextView TextAction { get; }
-        public TextField TextHelp { get; }
-        public TextField TextHotKey { get; }
-        public TextField TextShortcutKey { get; }
-        public TextField TextTitle { get; }
-
-        public Action CreateAction (MenuItem menuItem, DynamicMenuItem item)
-        {
-            switch (menuItem.CheckType)
-            {
-                case MenuItemCheckStyle.NoCheck:
-                    return () => MessageBox.ErrorQuery (item.Title, item.Action, "Ok");
-                case MenuItemCheckStyle.Checked:
-                    return menuItem.ToggleChecked;
-                case MenuItemCheckStyle.Radio:
-                    break;
-            }
-
-            return () =>
-                   {
-                       menuItem.Checked = true;
-                       var parent = menuItem?.Parent as MenuBarItem;
-
-                       if (parent != null)
-                       {
-                           MenuItem [] childrens = parent.Children;
-
-                           for (var i = 0; i < childrens.Length; i++)
-                           {
-                               MenuItem child = childrens [i];
-
-                               if (child != menuItem)
-                               {
-                                   child.Checked = false;
-                               }
-                           }
-                       }
-                   };
-        }
-
-        public void EditMenuBarItem (MenuItem menuItem)
-        {
-            if (menuItem == null)
-            {
-                _hasParent = false;
-                Enabled = false;
-                CleanEditMenuBarItem ();
-
-                return;
-            }
-
-            _hasParent = menuItem.Parent != null;
-            Enabled = true;
-            _menuItem = menuItem;
-            TextTitle.Text = menuItem?.Title ?? "";
-            TextHelp.Text = menuItem?.Help ?? "";
-
-            TextAction.Text = menuItem.Action != null
-                                  ? GetTargetAction (menuItem.Action)
-                                  : string.Empty;
-            TextHotKey.Text = menuItem?.HotKey != Key.Empty ? menuItem.HotKey.ToString () : "";
-            CkbIsTopLevel.CheckedState = IsTopLevel (menuItem) ? CheckState.Checked : CheckState.UnChecked;
-            CkbSubMenu.CheckedState = HasSubMenus (menuItem) ? CheckState.Checked : CheckState.UnChecked;
-            CkbNullCheck.CheckedState = menuItem.AllowNullChecked ? CheckState.Checked : CheckState.UnChecked;
-            TextHelp.Enabled = CkbSubMenu.CheckedState == CheckState.UnChecked;
-            TextAction.Enabled = CkbSubMenu.CheckedState == CheckState.UnChecked;
-            RbChkStyle.SelectedItem = (int)(menuItem?.CheckType ?? MenuItemCheckStyle.NoCheck);
-            TextShortcutKey.Text = menuItem?.ShortcutTag ?? "";
-
-            TextShortcutKey.Enabled = CkbIsTopLevel.CheckedState == CheckState.Checked && CkbSubMenu.CheckedState == CheckState.UnChecked
-                                   || CkbIsTopLevel.CheckedState == CheckState.UnChecked && CkbSubMenu.CheckedState == CheckState.UnChecked;
-        }
-
-        public DynamicMenuItem EnterMenuItem ()
-        {
-            var valid = false;
-
-            if (_menuItem == null)
-            {
-                var m = new DynamicMenuItem ();
-                TextTitle.Text = m.Title;
-                TextHelp.Text = m.Help;
-                TextAction.Text = m.Action;
-                TextHotKey.Text = m.HotKey ?? string.Empty;
-                CkbIsTopLevel.CheckedState = CheckState.UnChecked;
-                CkbSubMenu.CheckedState = !_hasParent ? CheckState.Checked : CheckState.UnChecked;
-                CkbNullCheck.CheckedState = CheckState.UnChecked;
-                TextHelp.Enabled = _hasParent;
-                TextAction.Enabled = _hasParent;
-                TextShortcutKey.Enabled = _hasParent;
-            }
-            else
-            {
-                EditMenuBarItem (_menuItem);
-            }
-
-            var btnOk = new Button { IsDefault = true, Text = "Ok" };
-
-            btnOk.Accepting += (s, e) =>
-                            {
-                                if (string.IsNullOrEmpty (TextTitle.Text))
-                                {
-                                    MessageBox.ErrorQuery ("Invalid title", "Must enter a valid title!.", "Ok");
-                                }
-                                else
-                                {
-                                    valid = true;
-                                    Application.RequestStop ();
-                                }
-                            };
-            var btnCancel = new Button { Text = "Cancel" };
-
-            btnCancel.Accepting += (s, e) =>
-                                {
-                                    TextTitle.Text = string.Empty;
-                                    Application.RequestStop ();
-                                };
-
-            var dialog = new Dialog
-                { Title = "Enter the menu details.", Buttons = [btnOk, btnCancel], Height = Dim.Auto (DimAutoStyle.Content, 23, Application.Screen.Height) };
-
-            Width = Dim.Fill ();
-            Height = Dim.Fill () - 2;
-            dialog.Add (this);
-            TextTitle.SetFocus ();
-            TextTitle.CursorPosition = TextTitle.Text.Length;
-            Application.Run (dialog);
-            dialog.Dispose ();
-
-            if (valid)
-            {
-                return new ()
-                {
-                    Title = TextTitle.Text,
-                    Help = TextHelp.Text,
-                    Action = TextAction.Text,
-                    HotKey = TextHotKey.Text,
-                    IsTopLevel = CkbIsTopLevel?.CheckedState == CheckState.Checked,
-                    HasSubMenu = CkbSubMenu?.CheckedState == CheckState.Checked,
-                    CheckStyle = RbChkStyle.SelectedItem == 0 ? MenuItemCheckStyle.NoCheck :
-                                 RbChkStyle.SelectedItem == 1 ? MenuItemCheckStyle.Checked :
-                                 MenuItemCheckStyle.Radio,
-                    ShortcutKey = TextShortcutKey.Text,
-                    AllowNullChecked = CkbNullCheck?.CheckedState == CheckState.Checked,
-                };
-            }
-
-            return null;
-        }
-
-        public void UpdateParent (ref MenuItem menuItem)
-        {
-            var parent = menuItem.Parent as MenuBarItem;
-            int idx = parent.GetChildrenIndex (menuItem);
-
-            if (!(menuItem is MenuBarItem))
-            {
-                menuItem = new MenuBarItem (menuItem.Title, new MenuItem [] { }, menuItem.Parent);
-
-                if (idx > -1)
-                {
-                    parent.Children [idx] = menuItem;
-                }
-            }
-            else
-            {
-                menuItem = new (
-                                menuItem.Title,
-                                menuItem.Help,
-                                CreateAction (menuItem, new ()),
-                                null,
-                                menuItem.Parent
-                               );
-
-                if (idx > -1)
-                {
-                    parent.Children [idx] = menuItem;
-                }
-            }
-        }
-
-        private void CleanEditMenuBarItem ()
-        {
-            TextTitle.Text = "";
-            TextHelp.Text = "";
-            TextAction.Text = "";
-            TextHotKey.Text = "";
-            CkbIsTopLevel.CheckedState = CheckState.UnChecked;
-            CkbSubMenu.CheckedState = CheckState.UnChecked;
-            RbChkStyle.SelectedItem = (int)MenuItemCheckStyle.NoCheck;
-            TextShortcutKey.Text = "";
-        }
-
-        private string GetTargetAction (Action action)
-        {
-            object me = action.Target;
-
-            if (me == null)
-            {
-                throw new ArgumentException ();
-            }
-
-            var v = new object ();
-
-            foreach (FieldInfo field in me.GetType ().GetFields ())
-            {
-                if (field.Name == "item")
-                {
-                    v = field.GetValue (me);
-                }
-            }
-
-            return v == null || !(v is DynamicMenuItem item) ? string.Empty : item.Action;
-        }
-
-        private bool HasSubMenus (MenuItem menuItem)
-        {
-            var menuBarItem = menuItem as MenuBarItem;
-
-            if (menuBarItem != null && menuBarItem.Children != null && (menuBarItem.Children.Length > 0 || menuBarItem.Action == null))
-            {
-                return true;
-            }
-
-            return false;
-        }
-
-        private bool IsTopLevel (MenuItem menuItem)
-        {
-            var topLevel = menuItem as MenuBarItem;
-
-            if (topLevel != null && topLevel.Parent == null && (topLevel.Children == null || topLevel.Children.Length == 0) && topLevel.Action != null)
-            {
-                return true;
-            }
-
-            return false;
-        }
-    }
-
-    public class DynamicMenuBarSample : Window
-    {
-        private readonly ListView _lstMenus;
-        private MenuItem _currentEditMenuBarItem;
-        private MenuItem _currentMenuBarItem;
-        private int _currentSelectedMenuBar;
-        private MenuBar _menuBar;
-
-        public DynamicMenuBarSample ()
-        {
-            DataContext = new ();
-
-            var frmDelimiter = new FrameView
-            {
-                X = Pos.Center (),
-                Y = 3,
-                Width = 25,
-                Height = 4,
-                Title = "Shortcut Delimiter:"
-            };
-
-            var txtDelimiter = new TextField
-            {
-                X = Pos.Center (), Width = 2, Text = Key.Separator.ToString ()
-            };
-
-
-            var frmMenu = new FrameView { Y = 7, Width = Dim.Percent (50), Height = Dim.Fill (), Title = "Menus:" };
-
-            var btnAddMenuBar = new Button { Y = 1, Text = "Add a MenuBar" };
-            frmMenu.Add (btnAddMenuBar);
-
-            var btnMenuBarUp = new Button { X = Pos.Center (), Text = Glyphs.UpArrow.ToString () };
-            frmMenu.Add (btnMenuBarUp);
-
-            var btnMenuBarDown = new Button { X = Pos.Center (), Y = Pos.Bottom (btnMenuBarUp), Text = Glyphs.DownArrow.ToString () };
-            frmMenu.Add (btnMenuBarDown);
-
-            var btnRemoveMenuBar = new Button { Y = 1, Text = "Remove a MenuBar" };
-
-            btnRemoveMenuBar.X = Pos.AnchorEnd (0) - (Pos.Right (btnRemoveMenuBar) - Pos.Left (btnRemoveMenuBar));
-            frmMenu.Add (btnRemoveMenuBar);
-
-            var btnPrevious = new Button
-            {
-                X = Pos.Left (btnAddMenuBar), Y = Pos.Top (btnAddMenuBar) + 2, Text = Glyphs.LeftArrow.ToString ()
-            };
-            frmMenu.Add (btnPrevious);
-
-            var btnAdd = new Button { Y = Pos.Top (btnPrevious) + 2, Text = " Add  " };
-            btnAdd.X = Pos.AnchorEnd ();
-            frmMenu.Add (btnAdd);
-
-            var btnNext = new Button { X = Pos.X (btnAdd), Y = Pos.Top (btnPrevious), Text = Glyphs.RightArrow.ToString () };
-            frmMenu.Add (btnNext);
-
-            var lblMenuBar = new Label
-            {
-                SchemeName = "Dialog",
-                TextAlignment = Alignment.Center,
-                X = Pos.Right (btnPrevious) + 1,
-                Y = Pos.Top (btnPrevious),
-
-                Width = Dim.Fill () - Dim.Func (_ => btnAdd.Frame.Width + 1),
-                Height = 1
-            };
-
-            lblMenuBar.TextChanged += (s, e) =>
-                                       {
-                                           if (lblMenuBar.Text.Contains ("_"))
-                                           {
-                                               lblMenuBar.Text = lblMenuBar.Text.Replace ("_", "");
-                                           }
-                                       };
-            frmMenu.Add (lblMenuBar);
-            lblMenuBar.WantMousePositionReports = true;
-            lblMenuBar.CanFocus = true;
-
-            var lblParent = new Label
-            {
-                TextAlignment = Alignment.Center,
-                X = Pos.Right (btnPrevious) + 1,
-                Y = Pos.Top (btnPrevious) + 1,
-
-                Width = Dim.Fill () - Dim.Width (btnAdd) - 1
-            };
-            frmMenu.Add (lblParent);
-
-            var btnPreviowsParent = new Button
-            {
-                X = Pos.Left (btnAddMenuBar), Y = Pos.Top (btnPrevious) + 1, Text = ".."
-            };
-            frmMenu.Add (btnPreviowsParent);
-
-            _lstMenus = new ()
-            {
-                SchemeName = "Dialog",
-                X = Pos.Right (btnPrevious) + 1,
-                Y = Pos.Top (btnPrevious) + 2,
-                Width = lblMenuBar.Width,
-                Height = Dim.Fill (),
-                Source = new ListWrapper<DynamicMenuItemList> ([])
-            };
-            frmMenu.Add (_lstMenus);
-
-            //lblMenuBar.TabIndex = btnPrevious.TabIndex + 1;
-            //_lstMenus.TabIndex = lblMenuBar.TabIndex + 1;
-            //btnNext.TabIndex = _lstMenus.TabIndex + 1;
-            //btnAdd.TabIndex = btnNext.TabIndex + 1;
-
-            var btnRemove = new Button { X = Pos.Left (btnAdd), Y = Pos.Top (btnAdd) + 1, Text = "Remove" };
-            frmMenu.Add (btnRemove);
-
-            var btnUp = new Button { X = Pos.Right (_lstMenus) + 2, Y = Pos.Top (btnRemove) + 2, Text = Glyphs.UpArrow.ToString () };
-            frmMenu.Add (btnUp);
-
-            var btnDown = new Button { X = Pos.Right (_lstMenus) + 2, Y = Pos.Top (btnUp) + 1, Text = Glyphs.DownArrow.ToString () };
-            frmMenu.Add (btnDown);
-
-            Add (frmMenu);
-
-            var frmMenuDetails = new DynamicMenuBarDetails
-            {
-                X = Pos.Right (frmMenu),
-                Y = Pos.Top (frmMenu),
-                Width = Dim.Fill (),
-                Height = Dim.Fill (2),
-                Title = "Menu Details:"
-            };
-            Add (frmMenuDetails);
-
-            btnMenuBarUp.Accepting += (s, e) =>
-                                    {
-                                        int i = _currentSelectedMenuBar;
-
-                                        MenuBarItem menuItem = _menuBar != null && _menuBar.Menus.Length > 0
-                                                                   ? _menuBar.Menus [i]
-                                                                   : null;
-
-                                        if (menuItem != null)
-                                        {
-                                            MenuBarItem [] menus = _menuBar.Menus;
-
-                                            if (i > 0)
-                                            {
-                                                menus [i] = menus [i - 1];
-                                                menus [i - 1] = menuItem;
-                                                _currentSelectedMenuBar = i - 1;
-                                                _menuBar.SetNeedsDraw ();
-                                            }
-                                        }
-                                    };
-
-            btnMenuBarDown.Accepting += (s, e) =>
-                                      {
-                                          int i = _currentSelectedMenuBar;
-
-                                          MenuBarItem menuItem = _menuBar != null && _menuBar.Menus.Length > 0
-                                                                     ? _menuBar.Menus [i]
-                                                                     : null;
-
-                                          if (menuItem != null)
-                                          {
-                                              MenuBarItem [] menus = _menuBar.Menus;
-
-                                              if (i < menus.Length - 1)
-                                              {
-                                                  menus [i] = menus [i + 1];
-                                                  menus [i + 1] = menuItem;
-                                                  _currentSelectedMenuBar = i + 1;
-                                                  _menuBar.SetNeedsDraw ();
-                                              }
-                                          }
-                                      };
-
-            btnUp.Accepting += (s, e) =>
-                             {
-                                 int i = _lstMenus.SelectedItem;
-                                 MenuItem menuItem = DataContext.Menus.Count > 0 ? DataContext.Menus [i].MenuItem : null;
-
-                                 if (menuItem != null)
-                                 {
-                                     MenuItem [] childrens = ((MenuBarItem)_currentMenuBarItem).Children;
-
-                                     if (i > 0)
-                                     {
-                                         childrens [i] = childrens [i - 1];
-                                         childrens [i - 1] = menuItem;
-                                         DataContext.Menus [i] = DataContext.Menus [i - 1];
-
-                                         DataContext.Menus [i - 1] =
-                                             new () { Title = menuItem.Title, MenuItem = menuItem };
-                                         _lstMenus.SelectedItem = i - 1;
-                                     }
-                                 }
-                             };
-
-            btnDown.Accepting += (s, e) =>
-                               {
-                                   int i = _lstMenus.SelectedItem;
-                                   MenuItem menuItem = DataContext.Menus.Count > 0 ? DataContext.Menus [i].MenuItem : null;
-
-                                   if (menuItem != null)
-                                   {
-                                       MenuItem [] childrens = ((MenuBarItem)_currentMenuBarItem).Children;
-
-                                       if (i < childrens.Length - 1)
-                                       {
-                                           childrens [i] = childrens [i + 1];
-                                           childrens [i + 1] = menuItem;
-                                           DataContext.Menus [i] = DataContext.Menus [i + 1];
-
-                                           DataContext.Menus [i + 1] =
-                                               new () { Title = menuItem.Title, MenuItem = menuItem };
-                                           _lstMenus.SelectedItem = i + 1;
-                                       }
-                                   }
-                               };
-
-            btnPreviowsParent.Accepting += (s, e) =>
-                                         {
-                                             if (_currentMenuBarItem != null && _currentMenuBarItem.Parent != null)
-                                             {
-                                                 MenuItem mi = _currentMenuBarItem;
-                                                 _currentMenuBarItem = _currentMenuBarItem.Parent as MenuBarItem;
-                                                 SetListViewSource (_currentMenuBarItem, true);
-                                                 int i = ((MenuBarItem)_currentMenuBarItem).GetChildrenIndex (mi);
-
-                                                 if (i > -1)
-                                                 {
-                                                     _lstMenus.SelectedItem = i;
-                                                 }
-
-                                                 if (_currentMenuBarItem.Parent != null)
-                                                 {
-                                                     DataContext.Parent = _currentMenuBarItem.Title;
-                                                 }
-                                                 else
-                                                 {
-                                                     DataContext.Parent = string.Empty;
-                                                 }
-                                             }
-                                             else
-                                             {
-                                                 DataContext.Parent = string.Empty;
-                                             }
-                                         };
-
-            var btnOk = new Button { X = Pos.Right (frmMenu) + 20, Y = Pos.Bottom (frmMenuDetails), Text = "Ok" };
-            Add (btnOk);
-
-            var btnCancel = new Button { X = Pos.Right (btnOk) + 3, Y = Pos.Top (btnOk), Text = "Cancel" };
-            btnCancel.Accepting += (s, e) => { SetFrameDetails (_currentEditMenuBarItem); };
-            Add (btnCancel);
-
-            txtDelimiter.TextChanging += (s, e) =>
-                                          {
-                                              if (!string.IsNullOrEmpty (e.Result))
-                                              {
-                                                  Key.Separator = e.Result.ToRunes () [0];
-                                              }
-                                              else
-                                              {
-                                                  e.Handled = true;
-                                                  txtDelimiter.SelectAll ();
-                                              }
-                                          };
-            txtDelimiter.TextChanged += (s, _) =>
-                                         {
-                                             txtDelimiter.SelectAll ();
-                                             SetFrameDetails ();
-                                         };
-            frmDelimiter.Add (txtDelimiter);
-            txtDelimiter.SelectAll ();
-            Add (frmDelimiter);
-
-            _lstMenus.SelectedItemChanged += (s, e) => { SetFrameDetails (); };
-
-            btnOk.Accepting += (s, e) =>
-                             {
-                                 if (string.IsNullOrEmpty (frmMenuDetails.TextTitle.Text) && _currentEditMenuBarItem != null)
-                                 {
-                                     MessageBox.ErrorQuery ("Invalid title", "Must enter a valid title!.", "Ok");
-                                 }
-                                 else if (_currentEditMenuBarItem != null)
-                                 {
-                                     var menuItem = new DynamicMenuItem
-                                     {
-                                         Title = frmMenuDetails.TextTitle.Text,
-                                         Help = frmMenuDetails.TextHelp.Text,
-                                         Action = frmMenuDetails.TextAction.Text,
-                                         HotKey = frmMenuDetails.TextHotKey.Text,
-                                         IsTopLevel = frmMenuDetails.CkbIsTopLevel?.CheckedState == CheckState.Checked,
-                                         HasSubMenu = frmMenuDetails.CkbSubMenu?.CheckedState == CheckState.Checked,
-                                         CheckStyle = frmMenuDetails.RbChkStyle.SelectedItem == 0
-                                                          ? MenuItemCheckStyle.NoCheck
-                                                          : frmMenuDetails.RbChkStyle.SelectedItem == 1
-                                                              ? MenuItemCheckStyle.Checked
-                                                              : MenuItemCheckStyle.Radio,
-                                         ShortcutKey = frmMenuDetails.TextShortcutKey.Text
-                                     };
-                                     UpdateMenuItem (_currentEditMenuBarItem, menuItem, _lstMenus.SelectedItem);
-                                 }
-                             };
-
-            btnAdd.Accepting += (s, e) =>
-                              {
-                                  if (MenuBar == null)
-                                  {
-                                      MessageBox.ErrorQuery ("Menu Bar Error", "Must add a MenuBar first!", "Ok");
-                                      btnAddMenuBar.SetFocus ();
-
-                                      return;
-                                  }
-
-                                  var frameDetails = new DynamicMenuBarDetails (null, _currentMenuBarItem != null);
-                                  DynamicMenuItem item = frameDetails.EnterMenuItem ();
-
-                                  if (item == null)
-                                  {
-                                      return;
-                                  }
-
-                                  if (_currentMenuBarItem is not MenuBarItem)
-                                  {
-                                      var parent = _currentMenuBarItem.Parent as MenuBarItem;
-                                      int idx = parent.GetChildrenIndex (_currentMenuBarItem);
-
-                                      _currentMenuBarItem = new MenuBarItem (
-                                                                             _currentMenuBarItem.Title,
-                                                                             new MenuItem [] { },
-                                                                             _currentMenuBarItem.Parent
-                                                                            );
-                                      _currentMenuBarItem.CheckType = item.CheckStyle;
-                                      parent.Children [idx] = _currentMenuBarItem;
-                                  }
-                                  else
-                                  {
-                                      MenuItem newMenu = CreateNewMenu (item, _currentMenuBarItem);
-                                      var menuBarItem = _currentMenuBarItem as MenuBarItem;
-                                      menuBarItem.AddMenuBarItem (MenuBar, newMenu);
-
-
-                                      DataContext.Menus.Add (new () { Title = newMenu.Title, MenuItem = newMenu });
-                                      _lstMenus.MoveDown ();
-                                  }
-                              };
-
-            btnRemove.Accepting += (s, e) =>
-                                {
-                                    MenuItem menuItem = (DataContext.Menus.Count > 0 && _lstMenus.SelectedItem > -1
-                                                             ? DataContext.Menus [_lstMenus.SelectedItem].MenuItem
-                                                             : _currentEditMenuBarItem);
-
-                                    if (menuItem != null)
-                                    {
-                                        menuItem.RemoveMenuItem ();
-
-                                        if (_currentEditMenuBarItem == menuItem)
-                                        {
-                                            _currentEditMenuBarItem = null;
-
-                                            if (menuItem.Parent is null)
-                                            {
-                                                _currentSelectedMenuBar = Math.Max (Math.Min (_currentSelectedMenuBar, _menuBar.Menus.Length - 1), 0);
-                                            }
-
-                                            SelectCurrentMenuBarItem ();
-                                        }
-
-                                        if (_lstMenus.SelectedItem > -1)
-                                        {
-                                            DataContext.Menus?.RemoveAt (_lstMenus.SelectedItem);
-                                        }
-
-                                        if (_lstMenus.Source.Count > 0 && _lstMenus.SelectedItem > _lstMenus.Source.Count - 1)
-                                        {
-                                            _lstMenus.SelectedItem = _lstMenus.Source.Count - 1;
-                                        }
-
-                                        if (_menuBar.Menus.Length == 0)
-                                        {
-                                            RemoveMenuBar ();
-                                        }
-
-                                        _lstMenus.SetNeedsDraw ();
-                                        SetFrameDetails ();
-                                    }
-                                };
-
-            _lstMenus.OpenSelectedItem += (s, e) =>
-                                          {
-                                              _currentMenuBarItem = DataContext.Menus [e.Item].MenuItem;
-
-                                              if (!(_currentMenuBarItem is MenuBarItem))
-                                              {
-                                                  MessageBox.ErrorQuery ("Menu Open Error", "Must allows sub menus first!", "Ok");
-
-                                                  return;
-                                              }
-
-                                              DataContext.Parent = _currentMenuBarItem.Title;
-                                              DataContext.Menus = new ();
-                                              SetListViewSource (_currentMenuBarItem, true);
-                                              MenuItem menuBarItem = DataContext.Menus.Count > 0 ? DataContext.Menus [0].MenuItem : null;
-                                              SetFrameDetails (menuBarItem);
-                                          };
-
-            _lstMenus.HasFocusChanging += (s, e) =>
-                               {
-                                   MenuItem menuBarItem = _lstMenus.SelectedItem > -1 && DataContext.Menus.Count > 0
-                                                              ? DataContext.Menus [_lstMenus.SelectedItem].MenuItem
-                                                              : null;
-                                   SetFrameDetails (menuBarItem);
-                               };
-
-            btnNext.Accepting += (s, e) =>
-                               {
-                                   if (_menuBar != null && _currentSelectedMenuBar + 1 < _menuBar.Menus.Length)
-                                   {
-                                       _currentSelectedMenuBar++;
-                                   }
-
-                                   SelectCurrentMenuBarItem ();
-                               };
-
-            btnPrevious.Accepting += (s, e) =>
-                                   {
-                                       if (_currentSelectedMenuBar - 1 > -1)
-                                       {
-                                           _currentSelectedMenuBar--;
-                                       }
-
-                                       SelectCurrentMenuBarItem ();
-                                   };
-
-            lblMenuBar.HasFocusChanging += (s, e) =>
-                                 {
-                                     if (_menuBar?.Menus != null)
-                                     {
-                                         _currentMenuBarItem = _menuBar.Menus [_currentSelectedMenuBar];
-                                         SetFrameDetails (_menuBar.Menus [_currentSelectedMenuBar]);
-                                     }
-                                 };
-
-            btnAddMenuBar.Accepting += (s, e) =>
-                                     {
-                                         var frameDetails = new DynamicMenuBarDetails (null);
-                                         DynamicMenuItem item = frameDetails.EnterMenuItem ();
-
-                                         if (item == null)
-                                         {
-                                             return;
-                                         }
-
-                                         if (MenuBar == null)
-                                         {
-                                             _menuBar = new ();
-                                             Add (_menuBar);
-                                         }
-
-                                         var newMenu = CreateNewMenu (item) as MenuBarItem;
-                                         newMenu.AddMenuBarItem (MenuBar);
-
-                                         _currentMenuBarItem = newMenu;
-                                         _currentMenuBarItem.CheckType = item.CheckStyle;
-
-                                         if (Key.TryParse (item.ShortcutKey, out Key key))
-                                         {
-                                             _currentMenuBarItem.ShortcutKey = key;
-                                         }
-
-                                         _currentSelectedMenuBar = _menuBar.Menus.Length - 1;
-                                         _menuBar.Menus [_currentSelectedMenuBar] = newMenu;
-                                         lblMenuBar.Text = newMenu.Title;
-                                         SetListViewSource (_currentMenuBarItem, true);
-                                         SetFrameDetails (_menuBar.Menus [_currentSelectedMenuBar]);
-                                         _menuBar.SetNeedsDraw ();
-                                     };
-
-            btnRemoveMenuBar.Accepting += (s, e) =>
-                                        {
-                                            if (_menuBar == null)
-                                            {
-                                                return;
-                                            }
-
-                                            if (_menuBar != null && _menuBar.Menus.Length > 0)
-                                            {
-                                                _currentMenuBarItem.RemoveMenuItem ();
-
-
-
-                                                if (_currentSelectedMenuBar - 1 >= 0 && _menuBar.Menus.Length > 0)
-                                                {
-                                                    _currentSelectedMenuBar--;
-                                                }
-
-                                                _currentMenuBarItem = _menuBar.Menus?.Length > 0
-                                                                          ? _menuBar.Menus [_currentSelectedMenuBar]
-                                                                          : null;
-                                            }
-
-                                            RemoveMenuBar ();
-
-                                            SetListViewSource (_currentMenuBarItem, true);
-                                            SetFrameDetails ();
-                                        };
-
-            void RemoveMenuBar ()
-            {
-                if (MenuBar != null && _currentMenuBarItem == null && _menuBar.Menus.Length == 0)
-                {
-                    Remove (_menuBar);
-                    _menuBar.Dispose ();
-                    _menuBar = null;
-                    DataContext.Menus = new ();
-                    _currentMenuBarItem = null;
-                    _currentSelectedMenuBar = -1;
-                    lblMenuBar.Text = string.Empty;
-                }
-                else
-                {
-                    lblMenuBar.Text = _menuBar.Menus [_currentSelectedMenuBar].Title;
-                }
-            }
-
-            SetFrameDetails ();
-
-            var ustringConverter = new UStringValueConverter ();
-            ListWrapperConverter<DynamicMenuItemList> listWrapperConverter = new ListWrapperConverter<DynamicMenuItemList> ();
-
-            var bdgMenuBar = new Binding (this, "MenuBar", lblMenuBar, "Text", ustringConverter);
-            var bdgParent = new Binding (this, "Parent", lblParent, "Text", ustringConverter);
-            var bdgMenus = new Binding (this, "Menus", _lstMenus, "Source", listWrapperConverter);
-
-            void SetFrameDetails (MenuItem menuBarItem = null)
-            {
-                MenuItem menuItem;
-
-                if (menuBarItem == null)
-                {
-                    menuItem = _lstMenus.SelectedItem > -1 && DataContext.Menus.Count > 0
-                                   ? DataContext.Menus [_lstMenus.SelectedItem].MenuItem
-                                   : _currentEditMenuBarItem;
-                }
-                else
-                {
-                    menuItem = menuBarItem;
-                }
-
-                _currentEditMenuBarItem = menuItem;
-                frmMenuDetails.EditMenuBarItem (menuItem);
-                bool f = btnOk.Enabled == frmMenuDetails.Enabled;
-
-                if (!f)
-                {
-                    btnOk.Enabled = frmMenuDetails.Enabled;
-                    btnCancel.Enabled = frmMenuDetails.Enabled;
-                }
-            }
-
-            void SelectCurrentMenuBarItem ()
-            {
-                MenuBarItem menuBarItem = null;
-
-                if (_menuBar?.Menus is { Length: > 0 })
-                {
-                    menuBarItem = _menuBar.Menus [_currentSelectedMenuBar];
-                    lblMenuBar.Text = menuBarItem.Title;
-                }
-
-                SetFrameDetails (menuBarItem);
-                _currentMenuBarItem = menuBarItem;
-                DataContext.Menus = new ();
-                SetListViewSource (_currentMenuBarItem, true);
-                lblParent.Text = string.Empty;
-
-                if (_currentMenuBarItem is null)
-                {
-                    lblMenuBar.Text = string.Empty;
-                }
-            }
-
-            void SetListViewSource (MenuItem currentMenuBarItem, bool fill = false)
-            {
-                DataContext.Menus = [];
-                var menuBarItem = currentMenuBarItem as MenuBarItem;
-
-                if (menuBarItem != null && menuBarItem?.Children == null)
-                {
-                    return;
-                }
-
-                if (!fill)
-                {
-                    return;
-                }
-
-                if (menuBarItem != null)
-                {
-                    foreach (MenuItem child in menuBarItem?.Children)
-                    {
-                        var m = new DynamicMenuItemList { Title = child.Title, MenuItem = child };
-                        DataContext.Menus.Add (m);
-                    }
-                }
-            }
-
-            MenuItem CreateNewMenu (DynamicMenuItem item, MenuItem parent = null)
-            {
-                MenuItem newMenu;
-
-                if (item.HasSubMenu)
-                {
-                    newMenu = new MenuBarItem (item.Title, new MenuItem [] { }, parent);
-                }
-                else if (parent != null)
-                {
-                    newMenu = new (item.Title, item.Help, null, null, parent);
-                    newMenu.CheckType = item.CheckStyle;
-                    newMenu.Action = frmMenuDetails.CreateAction (newMenu, item);
-
-                    if (Key.TryParse (item.ShortcutKey, out Key key))
-                    {
-                        newMenu.ShortcutKey = key;
-                    }
-                    newMenu.AllowNullChecked = item.AllowNullChecked;
-                }
-                else if (item.IsTopLevel)
-                {
-                    newMenu = new MenuBarItem (item.Title, item.Help, null);
-                    newMenu.Action = frmMenuDetails.CreateAction (newMenu, item);
-
-                    if (Key.TryParse (item.ShortcutKey, out Key key))
-                    {
-                        newMenu.ShortcutKey = key;
-                    }
-                }
-                else
-                {
-                    newMenu = new MenuBarItem (item.Title, item.Help, null);
-
-                    ((MenuBarItem)newMenu).Children [0].Action =
-                        frmMenuDetails.CreateAction (newMenu, item);
-
-                    if (Key.TryParse (item.ShortcutKey, out Key key))
-                    {
-                        ((MenuBarItem)newMenu).Children [0].ShortcutKey = key;
-                    }
-                }
-
-                return newMenu;
-            }
-
-            void UpdateMenuItem (MenuItem currentEditMenuBarItem, DynamicMenuItem menuItem, int index)
-            {
-                currentEditMenuBarItem.Title = menuItem.Title;
-                currentEditMenuBarItem.Help = menuItem.Help;
-                currentEditMenuBarItem.CheckType = menuItem.CheckStyle;
-
-                if (currentEditMenuBarItem.Parent is MenuBarItem parent
-                    && parent.Children.Length == 1
-                    && currentEditMenuBarItem.CheckType == MenuItemCheckStyle.Radio)
-                {
-                    currentEditMenuBarItem.Checked = true;
-                }
-
-                if (menuItem.IsTopLevel && currentEditMenuBarItem is MenuBarItem)
-                {
-                    ((MenuBarItem)currentEditMenuBarItem).Children = null;
-
-                    currentEditMenuBarItem.Action =
-                        frmMenuDetails.CreateAction (currentEditMenuBarItem, menuItem);
-
-                    if (Key.TryParse (menuItem.ShortcutKey, out Key key))
-                    {
-                        currentEditMenuBarItem.ShortcutKey = key;
-                    }
-
-                    SetListViewSource (currentEditMenuBarItem, true);
-                }
-                else if (menuItem.HasSubMenu)
-                {
-                    currentEditMenuBarItem.Action = null;
-
-                    if (currentEditMenuBarItem is MenuBarItem && ((MenuBarItem)currentEditMenuBarItem).Children == null)
-                    {
-                        ((MenuBarItem)currentEditMenuBarItem).Children = new MenuItem [] { };
-                    }
-                    else if (currentEditMenuBarItem.Parent != null)
-                    {
-                        frmMenuDetails.UpdateParent (ref currentEditMenuBarItem);
-                    }
-                    else
-                    {
-                        currentEditMenuBarItem =
-                            new MenuBarItem (
-                                             currentEditMenuBarItem.Title,
-                                             new MenuItem [] { },
-                                             currentEditMenuBarItem.Parent
-                                            );
-                    }
-
-                    SetListViewSource (currentEditMenuBarItem, true);
-                }
-                else if (currentEditMenuBarItem is MenuBarItem && currentEditMenuBarItem.Parent != null)
-                {
-                    frmMenuDetails.UpdateParent (ref currentEditMenuBarItem);
-
-                    currentEditMenuBarItem = new (
-                                                   menuItem.Title,
-                                                   menuItem.Help,
-                                                   frmMenuDetails.CreateAction (currentEditMenuBarItem, menuItem),
-                                                   null,
-                                                   currentEditMenuBarItem.Parent
-                                                  );
-                }
-                else
-                {
-                    if (currentEditMenuBarItem is MenuBarItem)
-                    {
-                        ((MenuBarItem)currentEditMenuBarItem).Children = null;
-                        DataContext.Menus = new ();
-                    }
-
-                    currentEditMenuBarItem.Action =
-                        frmMenuDetails.CreateAction (currentEditMenuBarItem, menuItem);
-
-                    if (Key.TryParse (menuItem.ShortcutKey, out Key key))
-                    {
-                        currentEditMenuBarItem.ShortcutKey = key;
-                    }
-                }
-
-                if (currentEditMenuBarItem.Parent == null)
-                {
-                    DataContext.MenuBar = currentEditMenuBarItem.Title;
-                }
-                else
-                {
-                    if (DataContext.Menus.Count == 0)
-                    {
-                        DataContext.Menus.Add (
-                                               new ()
-                                               {
-                                                   Title = currentEditMenuBarItem.Title, MenuItem = currentEditMenuBarItem
-                                               }
-                                              );
-                    }
-
-                    DataContext.Menus [index] =
-                        new ()
-                        {
-                            Title = currentEditMenuBarItem.Title, MenuItem = currentEditMenuBarItem
-                        };
-                }
-
-                currentEditMenuBarItem.CheckType = menuItem.CheckStyle;
-                SetFrameDetails (currentEditMenuBarItem);
-            }
-
-            //_frmMenuDetails.Initialized += (s, e) => _frmMenuDetails.Enabled = false;
-        }
-
-        public DynamicMenuItemModel DataContext { get; set; }
-    }
-
-    public class DynamicMenuItem
-    {
-        public string Action { get; set; } = string.Empty;
-        public bool AllowNullChecked { get; set; }
-        public MenuItemCheckStyle CheckStyle { get; set; }
-        public bool HasSubMenu { get; set; }
-        public string Help { get; set; } = string.Empty;
-        public bool IsTopLevel { get; set; }
-        public string HotKey { get; set; }
-        public string ShortcutKey { get; set; }
-        public string Title { get; set; } = "_New";
-    }
-
-    public class DynamicMenuItemList
-    {
-        public MenuItem MenuItem { get; set; }
-        public string Title { get; set; }
-        public override string ToString () { return $"{Title}, {MenuItem.HotKey}, {MenuItem.ShortcutKey} "; }
-    }
-
-    public class DynamicMenuItemModel : INotifyPropertyChanged
-    {
-        private string _menuBar;
-        private ObservableCollection<DynamicMenuItemList> _menus;
-        private string _parent;
-        public DynamicMenuItemModel () { Menus = []; }
-
-        public string MenuBar
-        {
-            get => _menuBar;
-            set
-            {
-                if (value == _menuBar)
-                {
-                    return;
-                }
-
-                _menuBar = value;
-
-                PropertyChanged?.Invoke (
-                                         this,
-                                         new (GetPropertyName ())
-                                        );
-            }
-        }
-
-        public ObservableCollection<DynamicMenuItemList> Menus
-        {
-            get => _menus;
-            set
-            {
-                if (value == _menus)
-                {
-                    return;
-                }
-
-                _menus = value;
-
-                PropertyChanged?.Invoke (
-                                         this,
-                                         new (GetPropertyName ())
-                                        );
-            }
-        }
-
-        public string Parent
-        {
-            get => _parent;
-            set
-            {
-                if (value == _parent)
-                {
-                    return;
-                }
-
-                _parent = value;
-
-                PropertyChanged?.Invoke (
-                                         this,
-                                         new (GetPropertyName ())
-                                        );
-            }
-        }
-
-        public event PropertyChangedEventHandler PropertyChanged;
-        public string GetPropertyName ([CallerMemberName] string propertyName = null) { return propertyName; }
-    }
-
-    public interface IValueConverter
-    {
-        object Convert (object value, object parameter = null);
-    }
-
-    public class ListWrapperConverter<T> : IValueConverter
-    {
-        public object Convert (object value, object parameter = null) { return new ListWrapper<T> ((ObservableCollection<T>)value); }
-    }
-
-    public class UStringValueConverter : IValueConverter
-    {
-        public object Convert (object value, object parameter = null)
-        {
-            byte [] data = Encoding.ASCII.GetBytes (value.ToString () ?? string.Empty);
-
-            return StringExtensions.ToString (data);
-        }
-    }
-}

+ 27 - 14
Examples/UICatalog/Scenarios/DynamicStatusBar.cs

@@ -15,7 +15,7 @@ public class DynamicStatusBar : Scenario
     public override void Main ()
     {
         Application.Init ();
-        Application.Run<DynamicStatusBarSample> ().Dispose ();
+        Application.Run<DynamicStatusBarSample> ();
         Application.Shutdown ();
     }
 
@@ -79,7 +79,7 @@ public class DynamicStatusBar : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery ("Binding Error", $"Binding failed: {ex}.", "Ok");
+                MessageBox.ErrorQuery (ApplicationImpl.Instance, "Binding Error", $"Binding failed: {ex}.", "Ok");
             }
         }
     }
@@ -140,7 +140,7 @@ public class DynamicStatusBar : Scenario
         public TextView TextAction { get; }
         public TextField TextShortcut { get; }
         public TextField TextTitle { get; }
-        public Action CreateAction (DynamicStatusItem item) { return () => MessageBox.ErrorQuery (item.Title, item.Action, "Ok"); }
+        public Action CreateAction (DynamicStatusItem item) { return () => MessageBox.ErrorQuery (ApplicationImpl.Instance, item.Title, item.Action, "Ok"); }
 
         public void EditStatusItem (Shortcut statusItem)
         {
@@ -184,7 +184,7 @@ public class DynamicStatusBar : Scenario
                               {
                                   if (string.IsNullOrEmpty (TextTitle.Text))
                                   {
-                                      MessageBox.ErrorQuery ("Invalid title", "Must enter a valid title!.", "Ok");
+                                      MessageBox.ErrorQuery (App, "Invalid title", "Must enter a valid title!.", "Ok");
                                   }
                                   else
                                   {
@@ -200,7 +200,7 @@ public class DynamicStatusBar : Scenario
                                       TextTitle.Text = string.Empty;
                                       Application.RequestStop ();
                                   };
-            var dialog = new Dialog { Title = "Enter the menu details.", Buttons = [btnOk, btnCancel], Height = Dim.Auto (DimAutoStyle.Content, 17, Application.Screen.Height) };
+            var dialog = new Dialog { Title = "Enter the menu details.", Buttons = [btnOk, btnCancel], Height = Dim.Auto (DimAutoStyle.Content, 17, App?.Screen.Height) };
 
             Width = Dim.Fill ();
             Height = Dim.Fill () - 2;
@@ -312,7 +312,12 @@ public class DynamicStatusBar : Scenario
 
             btnUp.Accepting += (s, e) =>
                               {
-                                  int i = _lstItems.SelectedItem;
+                                  if (_lstItems.SelectedItem is null)
+                                  {
+                                      return;
+                                  }
+                                  int i = _lstItems.SelectedItem.Value;
+
                                   Shortcut statusItem = DataContext.Items.Count > 0 ? DataContext.Items [i].Shortcut : null;
 
                                   if (statusItem != null)
@@ -335,7 +340,12 @@ public class DynamicStatusBar : Scenario
 
             btnDown.Accepting += (s, e) =>
                                 {
-                                    int i = _lstItems.SelectedItem;
+                                    if (_lstItems.SelectedItem is null)
+                                    {
+                                        return;
+                                    }
+                                    int i = _lstItems.SelectedItem.Value;
+
                                     Shortcut statusItem = DataContext.Items.Count > 0 ? DataContext.Items [i].Shortcut : null;
 
                                     if (statusItem != null)
@@ -372,18 +382,21 @@ public class DynamicStatusBar : Scenario
                               {
                                   if (string.IsNullOrEmpty (frmStatusBarDetails.TextTitle.Text) && _currentEditStatusItem != null)
                                   {
-                                      MessageBox.ErrorQuery ("Invalid title", "Must enter a valid title!.", "Ok");
+                                      MessageBox.ErrorQuery (App, "Invalid title", "Must enter a valid title!.", "Ok");
                                   }
                                   else if (_currentEditStatusItem != null)
                                   {
-
                                       var statusItem = new DynamicStatusItem
                                       {
                                           Title = frmStatusBarDetails.TextTitle.Text,
                                           Action = frmStatusBarDetails.TextAction.Text,
                                           Shortcut = frmStatusBarDetails.TextShortcut.Text
                                       };
-                                      UpdateStatusItem (_currentEditStatusItem, statusItem, _lstItems.SelectedItem);
+
+                                      if (_lstItems.SelectedItem is { } selectedItem)
+                                      {
+                                          UpdateStatusItem (_currentEditStatusItem, statusItem, selectedItem);
+                                      }
                                   }
                               };
 
@@ -420,14 +433,14 @@ public class DynamicStatusBar : Scenario
             btnRemove.Accepting += (s, e) =>
                                   {
                                       Shortcut statusItem = DataContext.Items.Count > 0
-                                                                  ? DataContext.Items [_lstItems.SelectedItem].Shortcut
+                                                                  ? DataContext.Items [_lstItems.SelectedItem.Value].Shortcut
                                                                   : null;
 
                                       if (statusItem != null)
                                       {
                                           _statusBar.RemoveShortcut (_currentSelectedStatusBar);
                                           statusItem.Dispose ();
-                                          DataContext.Items.RemoveAt (_lstItems.SelectedItem);
+                                          DataContext.Items.RemoveAt (_lstItems.SelectedItem.Value);
 
                                           if (_lstItems.Source.Count > 0 && _lstItems.SelectedItem > _lstItems.Source.Count - 1)
                                           {
@@ -442,7 +455,7 @@ public class DynamicStatusBar : Scenario
             _lstItems.HasFocusChanging += (s, e) =>
                                {
                                    Shortcut statusItem = DataContext.Items.Count > 0
-                                                               ? DataContext.Items [_lstItems.SelectedItem].Shortcut
+                                                               ? DataContext.Items [_lstItems.SelectedItem.Value].Shortcut
                                                                : null;
                                    SetFrameDetails (statusItem);
                                };
@@ -489,7 +502,7 @@ public class DynamicStatusBar : Scenario
                 if (statusItem == null)
                 {
                     newStatusItem = DataContext.Items.Count > 0
-                                        ? DataContext.Items [_lstItems.SelectedItem].Shortcut
+                                        ? DataContext.Items [_lstItems.SelectedItem.Value].Shortcut
                                         : null;
                 }
                 else

文件差异内容过多而无法显示
+ 504 - 677
Examples/UICatalog/Scenarios/Editor.cs


+ 3 - 3
Examples/UICatalog/Scenarios/EditorsAndHelpers/AdornmentsEditor.cs

@@ -99,7 +99,7 @@ public class AdornmentsEditor : EditorBase
             SuperViewRendersLineCanvas = true,
             BorderStyle = LineStyle.Single
         };
-        MarginEditor.Border!.Thickness = MarginEditor.Border.Thickness with { Bottom = 0 };
+        MarginEditor.Border!.Thickness = MarginEditor.Border!.Thickness with { Bottom = 0 };
         Add (MarginEditor);
 
         BorderEditor = new ()
@@ -109,7 +109,7 @@ public class AdornmentsEditor : EditorBase
             SuperViewRendersLineCanvas = true,
             BorderStyle = LineStyle.Single
         };
-        BorderEditor.Border!.Thickness = BorderEditor.Border.Thickness with { Bottom = 0 };
+        BorderEditor.Border!.Thickness = BorderEditor.Border!.Thickness with { Bottom = 0 };
         Add (BorderEditor);
 
         PaddingEditor = new ()
@@ -119,7 +119,7 @@ public class AdornmentsEditor : EditorBase
             SuperViewRendersLineCanvas = true,
             BorderStyle = LineStyle.Single
         };
-        PaddingEditor.Border!.Thickness = PaddingEditor.Border.Thickness with { Bottom = 0 };
+        PaddingEditor.Border!.Thickness = PaddingEditor.Border!.Thickness with { Bottom = 0 };
         Add (PaddingEditor);
 
         Width = Dim.Auto (maximumContentDim: Dim.Func (_ => MarginEditor.Frame.Width - 2));

+ 39 - 17
Examples/UICatalog/Scenarios/EditorsAndHelpers/AllViewsView.cs

@@ -4,6 +4,7 @@ namespace UICatalog.Scenarios;
 public class AllViewsView : View
 {
     private const int MAX_VIEW_FRAME_HEIGHT = 25;
+
     public AllViewsView ()
     {
         CanFocus = true;
@@ -24,6 +25,7 @@ public class AllViewsView : View
         AddCommand (Command.Down, () => ScrollVertical (1));
         AddCommand (Command.PageUp, () => ScrollVertical (-SubViews.OfType<FrameView> ().First ().Frame.Height));
         AddCommand (Command.PageDown, () => ScrollVertical (SubViews.OfType<FrameView> ().First ().Frame.Height));
+
         AddCommand (
                     Command.Start,
                     () =>
@@ -32,6 +34,7 @@ public class AllViewsView : View
 
                         return true;
                     });
+
         AddCommand (
                     Command.End,
                     () =>
@@ -65,12 +68,12 @@ public class AllViewsView : View
         MouseBindings.Add (MouseFlags.WheeledRight, Command.ScrollRight);
     }
 
-    /// <inheritdoc />
+    /// <inheritdoc/>
     public override void EndInit ()
     {
         base.EndInit ();
 
-        var allClasses = GetAllViewClassesCollection ();
+        List<Type> allClasses = GetAllViewClassesCollection ();
 
         View? previousView = null;
 
@@ -95,19 +98,6 @@ public class AllViewsView : View
         }
     }
 
-    private static List<Type> GetAllViewClassesCollection ()
-    {
-        List<Type> types = typeof (View).Assembly.GetTypes ()
-                                        .Where (
-                                                myType => myType is { IsClass: true, IsAbstract: false, IsPublic: true }
-                                                          && myType.IsSubclassOf (typeof (View)))
-                                        .ToList ();
-
-        types.Add (typeof (View));
-
-        return types;
-    }
-
     private View? CreateView (Type type)
     {
         // If we are to create a generic Type
@@ -125,12 +115,32 @@ public class AllViewsView : View
                 }
                 else
                 {
-                    typeArguments.Add (typeof (object));
+                    // Check if the generic parameter has constraints
+                    Type [] constraints = arg.GetGenericParameterConstraints ();
+
+                    if (constraints.Length > 0)
+                    {
+                        // Use the first constraint type to satisfy the constraint
+                        typeArguments.Add (constraints [0]);
+                    }
+                    else
+                    {
+                        typeArguments.Add (typeof (object));
+                    }
                 }
             }
 
             // And change what type we are instantiating from MyClass<T> to MyClass<object> or MyClass<T>
-            type = type.MakeGenericType (typeArguments.ToArray ());
+            try
+            {
+                type = type.MakeGenericType (typeArguments.ToArray ());
+            }
+            catch (ArgumentException ex)
+            {
+                Logging.Warning ($"Cannot create generic type {type} with arguments [{string.Join (", ", typeArguments.Select (t => t.Name))}]: {ex.Message}");
+
+                return null;
+            }
         }
 
         // Ensure the type does not contain any generic parameters
@@ -164,6 +174,18 @@ public class AllViewsView : View
         return view;
     }
 
+    private static List<Type> GetAllViewClassesCollection ()
+    {
+        List<Type> types = typeof (View).Assembly.GetTypes ()
+                                        .Where (myType => myType is { IsClass: true, IsAbstract: false, IsPublic: true }
+                                                          && myType.IsSubclassOf (typeof (View)))
+                                        .ToList ();
+
+        types.Add (typeof (View));
+
+        return types;
+    }
+
     private void OnViewInitialized (object? sender, EventArgs e)
     {
         if (sender is not View view)

+ 14 - 80
Examples/UICatalog/Scenarios/EditorsAndHelpers/ArrangementEditor.cs

@@ -1,7 +1,4 @@
 #nullable enable
-using System;
-using System.Collections.Generic;
-
 namespace UICatalog.Scenarios;
 
 /// <summary>
@@ -16,97 +13,39 @@ public sealed class ArrangementEditor : EditorBase
 
         Initialized += ArrangementEditor_Initialized;
 
-        _arrangementSlider.Options =
-        [
-            new SliderOption<ViewArrangement>
-            {
-                Legend = ViewArrangement.Movable.ToString (),
-                Data = ViewArrangement.Movable
-            },
-
-            new SliderOption<ViewArrangement>
-            {
-                Legend = ViewArrangement.LeftResizable.ToString (),
-                Data = ViewArrangement.LeftResizable
-            },
-
-            new SliderOption<ViewArrangement>
-            {
-                Legend = ViewArrangement.RightResizable.ToString (),
-                Data = ViewArrangement.RightResizable
-            },
-
-            new SliderOption<ViewArrangement>
-            {
-                Legend = ViewArrangement.TopResizable.ToString (),
-                Data = ViewArrangement.TopResizable
-            },
-
-            new SliderOption<ViewArrangement>
-            {
-                Legend = ViewArrangement.BottomResizable.ToString (),
-                Data = ViewArrangement.BottomResizable
-            },
-
-            new SliderOption<ViewArrangement>
-            {
-                Legend = ViewArrangement.Overlapped.ToString (),
-                Data = ViewArrangement.Overlapped
-            }
-        ];
-
-        Add (_arrangementSlider);
+        Add (_arrangementSelector);
     }
 
-    private readonly Slider<ViewArrangement> _arrangementSlider = new()
+    private readonly FlagSelector<ViewArrangement> _arrangementSelector = new ()
     {
-        Orientation = Orientation.Vertical,
-        UseMinimumSize = true,
-        Type = SliderType.Multiple,
-        AllowEmpty = true,
+        Orientation = Orientation.Vertical
     };
 
     protected override void OnViewToEditChanged ()
     {
-        _arrangementSlider.Enabled = ViewToEdit is not Adornment;
+        _arrangementSelector.Enabled = ViewToEdit is not Adornment;
 
-        _arrangementSlider.OptionsChanged -= ArrangementSliderOnOptionsChanged;
+        _arrangementSelector.ValueChanged -= ArrangementFlagsOnValueChanged;
 
         // Set the appropriate options in the slider based on _viewToEdit.Arrangement
         if (ViewToEdit is { })
         {
-            _arrangementSlider.Options.ForEach (
-                                                option =>
-                                                {
-                                                    _arrangementSlider.ChangeOption (
-                                                                                     _arrangementSlider.Options.IndexOf (option),
-                                                                                     (ViewToEdit.Arrangement & option.Data) == option.Data);
-                                                });
+            _arrangementSelector.Value = ViewToEdit.Arrangement;
         }
 
-        _arrangementSlider.OptionsChanged += ArrangementSliderOnOptionsChanged;
+        _arrangementSelector.ValueChanged += ArrangementFlagsOnValueChanged;
     }
 
-    private void ArrangementEditor_Initialized (object? sender, EventArgs e) { _arrangementSlider.OptionsChanged += ArrangementSliderOnOptionsChanged; }
-
-    private void ArrangementSliderOnOptionsChanged (object? sender, SliderEventArgs<ViewArrangement> e)
+    private void ArrangementFlagsOnValueChanged (object? sender, EventArgs<ViewArrangement?> e)
     {
-        if (ViewToEdit is { })
+        if (ViewToEdit is { } && e.Value is { })
         {
-            // Set the arrangement based on the selected options
-            var arrangement = ViewArrangement.Fixed;
-
-            foreach (KeyValuePair<int, SliderOption<ViewArrangement>> option in e.Options)
-            {
-                arrangement |= option.Value.Data;
-            }
-
-            ViewToEdit.Arrangement = arrangement;
+            ViewToEdit.Arrangement = (ViewArrangement)e.Value;
 
             if (ViewToEdit.Arrangement.HasFlag (ViewArrangement.Overlapped))
             {
                 ViewToEdit.ShadowStyle = ShadowStyle.Transparent;
-                ViewToEdit.SchemeName = "Toplevel";
+                ViewToEdit.SchemeName = "Runnable";
             }
             else
             {
@@ -114,14 +53,9 @@ public sealed class ArrangementEditor : EditorBase
                 ViewToEdit.SchemeName = ViewToEdit!.SuperView!.SchemeName;
             }
 
-            if (ViewToEdit.Arrangement.HasFlag (ViewArrangement.Movable))
-            {
-                ViewToEdit.BorderStyle = LineStyle.Double;
-            }
-            else
-            {
-                ViewToEdit.BorderStyle = LineStyle.Single;
-            }
+            ViewToEdit.BorderStyle = ViewToEdit.Arrangement.HasFlag (ViewArrangement.Movable) ? LineStyle.Double : LineStyle.Single;
         }
     }
+
+    private void ArrangementEditor_Initialized (object? sender, EventArgs e) { _arrangementSelector.ValueChanged += ArrangementFlagsOnValueChanged; }
 }

+ 14 - 13
Examples/UICatalog/Scenarios/EditorsAndHelpers/BorderEditor.cs

@@ -8,7 +8,7 @@ namespace UICatalog.Scenarios;
 public class BorderEditor : AdornmentEditor
 {
     private CheckBox? _ckbTitle;
-    private RadioGroup? _rbBorderStyle;
+    private OptionSelector<LineStyle>? _osBorderStyle;
     private CheckBox? _ckbGradient;
 
     public BorderEditor ()
@@ -21,34 +21,31 @@ public class BorderEditor : AdornmentEditor
     private void BorderEditor_AdornmentChanged (object? sender, EventArgs e)
     {
         _ckbTitle!.CheckedState = ((Border)AdornmentToEdit!).Settings.FastHasFlags (BorderSettings.Title) ? CheckState.Checked : CheckState.UnChecked;
-        _rbBorderStyle!.SelectedItem = (int)((Border)AdornmentToEdit).LineStyle;
+        _osBorderStyle!.Value = ((Border)AdornmentToEdit).LineStyle;
         _ckbGradient!.CheckedState = ((Border)AdornmentToEdit).Settings.FastHasFlags (BorderSettings.Gradient) ? CheckState.Checked : CheckState.UnChecked;
     }
 
     private void BorderEditor_Initialized (object? sender, EventArgs e)
     {
-        List<LineStyle> borderStyleEnum = Enum.GetValues (typeof (LineStyle)).Cast<LineStyle> ().ToList ();
-
-        _rbBorderStyle = new ()
+        _osBorderStyle = new ()
         {
             X = 0,
 
-            Y = Pos.Bottom (SubViews.ToArray() [^1]),
+            Y = Pos.Bottom (SubViews.ToArray () [^1]),
             Width = Dim.Fill (),
-            SelectedItem = (int)(((Border)AdornmentToEdit!)?.LineStyle ?? LineStyle.None),
+            Value = ((Border)AdornmentToEdit!)?.LineStyle ?? LineStyle.None,
             BorderStyle = LineStyle.Single,
             Title = "Border St_yle",
             SuperViewRendersLineCanvas = true,
-            RadioLabels = borderStyleEnum.Select (style => style.ToString ()).ToArray ()
         };
-        Add (_rbBorderStyle);
+        Add (_osBorderStyle);
 
-        _rbBorderStyle.SelectedItemChanged += OnRbBorderStyleOnSelectedItemChanged;
+        _osBorderStyle.ValueChanged += OnRbBorderStyleOnValueChanged;
 
         _ckbTitle = new ()
         {
             X = 0,
-            Y = Pos.Bottom (_rbBorderStyle),
+            Y = Pos.Bottom (_osBorderStyle),
 
             CheckedState = CheckState.Checked,
             SuperViewRendersLineCanvas = true,
@@ -73,10 +70,14 @@ public class BorderEditor : AdornmentEditor
 
         return;
 
-        void OnRbBorderStyleOnSelectedItemChanged (object? s, SelectedItemChangedArgs args)
+        void OnRbBorderStyleOnValueChanged (object? s, EventArgs<LineStyle?> args)
         {
             LineStyle prevBorderStyle = AdornmentToEdit!.BorderStyle;
-            ((Border)AdornmentToEdit).LineStyle = (LineStyle)args.SelectedItem!;
+
+            if (args.Value is { })
+            {
+                ((Border)AdornmentToEdit).LineStyle = (LineStyle)args.Value;
+            }
 
             if (((Border)AdornmentToEdit).LineStyle == LineStyle.None)
             {

+ 10 - 10
Examples/UICatalog/Scenarios/EditorsAndHelpers/DimEditor.cs

@@ -18,7 +18,7 @@ public class DimEditor : EditorBase
     }
 
     private int _value;
-    private RadioGroup? _dimRadioGroup;
+    private OptionSelector? _dimOptionSelector;
     private TextField? _valueEdit;
 
     /// <inheritdoc />
@@ -44,7 +44,7 @@ public class DimEditor : EditorBase
 
         try
         {
-            _dimRadioGroup!.SelectedItem = _dimNames.IndexOf (_dimNames.First (s => dim!.ToString ().StartsWith (s)));
+            _dimOptionSelector!.Value = _dimNames.IndexOf (_dimNames.First (s => dim!.ToString ().StartsWith (s)));
         }
         catch (InvalidOperationException e)
         {
@@ -92,13 +92,13 @@ public class DimEditor : EditorBase
             Text = $"{Title}:"
         };
         Add (label);
-        _dimRadioGroup = new () { X = 0, Y = Pos.Bottom (label), RadioLabels = _radioItems };
-        _dimRadioGroup.SelectedItemChanged += OnRadioGroupOnSelectedItemChanged;
+        _dimOptionSelector = new () { X = 0, Y = Pos.Bottom (label), Labels = _optionLabels };
+        _dimOptionSelector.ValueChanged += OnOptionSelectorOnValueChanged;
         _valueEdit = new ()
         {
             X = Pos.Right (label) + 1,
             Y = 0,
-            Width = Dim.Func (_ => _radioItems.Max (i => i.GetColumns ()) - label.Frame.Width + 1),
+            Width = Dim.Func (_ => _optionLabels.Max (i => i.GetColumns ()) - label.Frame.Width + 1),
             Text = $"{_value}"
         };
 
@@ -117,15 +117,15 @@ public class DimEditor : EditorBase
         };
         Add (_valueEdit);
 
-        Add (_dimRadioGroup);
+        Add (_dimOptionSelector);
 
     }
 
-    private void OnRadioGroupOnSelectedItemChanged (object? s, SelectedItemChangedArgs selected) { DimChanged (); }
+    private void OnOptionSelectorOnValueChanged (object? s, EventArgs<int?> selected) { DimChanged (); }
 
     // These need to have same order 
     private readonly List<string> _dimNames = ["Absolute", "Auto", "Fill", "Func", "Percent",];
-    private readonly string [] _radioItems = ["Absolute(n)", "Auto", "Fill(n)", "Func(()=>n)", "Percent(n)",];
+    private readonly string [] _optionLabels = ["Absolute(n)", "Auto", "Fill(n)", "Func(()=>n)", "Percent(n)",];
 
     private void DimChanged ()
     {
@@ -136,7 +136,7 @@ public class DimEditor : EditorBase
 
         try
         {
-            Dim? dim = _dimRadioGroup!.SelectedItem switch
+            Dim? dim = _dimOptionSelector!.Value switch
             {
                 0 => Dim.Absolute (_value),
                 1 => Dim.Auto (),
@@ -157,7 +157,7 @@ public class DimEditor : EditorBase
         }
         catch (Exception e)
         {
-            MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
+            MessageBox.ErrorQuery (App, "Exception", e.Message, "Ok");
         }
     }
 }

+ 14 - 22
Examples/UICatalog/Scenarios/EditorsAndHelpers/MarginEditor.cs

@@ -12,7 +12,7 @@ public class MarginEditor : AdornmentEditor
         AdornmentChanged += MarginEditor_AdornmentChanged;
     }
 
-    private RadioGroup? _rgShadow;
+    private OptionSelector<ShadowStyle>? _optionsShadow;
 
     private FlagSelector? _flagSelectorTransparent;
 
@@ -20,18 +20,18 @@ public class MarginEditor : AdornmentEditor
     {
         if (AdornmentToEdit is { })
         {
-            _rgShadow!.SelectedItem = (int)((Margin)AdornmentToEdit).ShadowStyle;
+            _optionsShadow!.Value = ((Margin)AdornmentToEdit).ShadowStyle;
         }
 
         if (AdornmentToEdit is { })
         {
-            _flagSelectorTransparent!.Value = (uint)((Margin)AdornmentToEdit).ViewportSettings;
+            _flagSelectorTransparent!.Value = (int)((Margin)AdornmentToEdit).ViewportSettings;
         }
     }
 
     private void MarginEditor_Initialized (object? sender, EventArgs e)
     {
-        _rgShadow = new RadioGroup
+        _optionsShadow = new ()
         {
             X = 0,
             Y = Pos.Bottom (SubViews.ElementAt(SubViews.Count-1)),
@@ -39,44 +39,36 @@ public class MarginEditor : AdornmentEditor
             SuperViewRendersLineCanvas = true,
             Title = "_Shadow",
             BorderStyle = LineStyle.Single,
-            RadioLabels = Enum.GetNames (typeof (ShadowStyle)),
+            AssignHotKeys = true
         };
 
         if (AdornmentToEdit is { })
         {
-            _rgShadow.SelectedItem = (int)((Margin)AdornmentToEdit).ShadowStyle;
+            _optionsShadow.Value = ((Margin)AdornmentToEdit).ShadowStyle;
         }
 
-        _rgShadow.SelectedItemChanged += (_, args) =>
-                                        {
-                                            ((Margin)AdornmentToEdit!).ShadowStyle = (ShadowStyle)args.SelectedItem!;
-                                        };
+        _optionsShadow.ValueChanged += (_, args) => ((Margin)AdornmentToEdit!).ShadowStyle = args.Value!.Value;
 
-        Add (_rgShadow);
+        Add (_optionsShadow);
 
-        var flags = new Dictionary<uint, string> ()
-        {
-            { (uint)Terminal.Gui.ViewBase.ViewportSettingsFlags.Transparent, "Transparent" },
-            { (uint)Terminal.Gui.ViewBase.ViewportSettingsFlags.TransparentMouse, "TransparentMouse" }
-        };
-
-        _flagSelectorTransparent = new FlagSelector ()
+        _flagSelectorTransparent = new FlagSelector<ViewportSettingsFlags> ()
         {
             X = 0,
-            Y = Pos.Bottom (_rgShadow),
+            Y = Pos.Bottom (_optionsShadow),
 
             SuperViewRendersLineCanvas = true,
             Title = "_ViewportSettings",
             BorderStyle = LineStyle.Single,
         };
-        _flagSelectorTransparent.SetFlags(flags.AsReadOnly ());
-
+        _flagSelectorTransparent.Values = [(int)ViewportSettingsFlags.Transparent, (int)ViewportSettingsFlags.TransparentMouse];
+        _flagSelectorTransparent.Labels = ["Transparent", "TransparentMouse"];
+        _flagSelectorTransparent.AssignHotKeys = true;
 
         Add (_flagSelectorTransparent);
 
         if (AdornmentToEdit is { })
         {
-            _flagSelectorTransparent.Value = (uint)((Margin)AdornmentToEdit).ViewportSettings;
+            _flagSelectorTransparent.Value = (int)((Margin)AdornmentToEdit).ViewportSettings;
         }
 
         _flagSelectorTransparent.ValueChanged += (_, args) =>

+ 10 - 10
Examples/UICatalog/Scenarios/EditorsAndHelpers/PosEditor.cs

@@ -19,7 +19,7 @@ public class PosEditor : EditorBase
     }
 
     private int _value;
-    private RadioGroup? _posRadioGroup;
+    private OptionSelector? _posOptionSelector;
     private TextField? _valueEdit;
 
     protected override void OnUpdateLayoutSettings ()
@@ -44,7 +44,7 @@ public class PosEditor : EditorBase
 
         try
         {
-            _posRadioGroup!.SelectedItem = _posNames.IndexOf (_posNames.First (s => pos.ToString ().Contains (s)));
+            _posOptionSelector!.Value = _posNames.IndexOf (_posNames.First (s => pos.ToString ().Contains (s)));
         }
         catch (InvalidOperationException e)
         {
@@ -91,14 +91,14 @@ public class PosEditor : EditorBase
             Text = $"{Title}:"
         };
         Add (label);
-        _posRadioGroup = new () { X = 0, Y = Pos.Bottom (label), RadioLabels = _radioItems };
-        _posRadioGroup.SelectedItemChanged += OnRadioGroupOnSelectedItemChanged;
+        _posOptionSelector = new () { X = 0, Y = Pos.Bottom (label), Labels = _optionLabels };
+        _posOptionSelector.ValueChanged += OnOptionSelectorOnValueChanged;
 
         _valueEdit = new ()
         {
             X = Pos.Right (label) + 1,
             Y = 0,
-            Width = Dim.Func (_ => _radioItems.Max (i => i.GetColumns ()) - label.Frame.Width + 1),
+            Width = Dim.Func (_ => _optionLabels.Max (i => i.GetColumns ()) - label.Frame.Width + 1),
             Text = $"{_value}"
         };
 
@@ -118,14 +118,14 @@ public class PosEditor : EditorBase
                                 };
         Add (_valueEdit);
 
-        Add (_posRadioGroup);
+        Add (_posOptionSelector);
     }
 
-    private void OnRadioGroupOnSelectedItemChanged (object? s, SelectedItemChangedArgs selected) { PosChanged (); }
+    private void OnOptionSelectorOnValueChanged (object? s, EventArgs<int?> selected) { PosChanged (); }
 
     // These need to have same order 
     private readonly List<string> _posNames = ["Absolute", "Align", "AnchorEnd", "Center", "Func", "Percent"];
-    private readonly string [] _radioItems = ["Absolute(n)", "Align", "AnchorEnd", "Center", "Func(()=>n)", "Percent(n)"];
+    private readonly string [] _optionLabels = ["Absolute(n)", "Align", "AnchorEnd", "Center", "Func(()=>n)", "Percent(n)"];
 
     private void PosChanged ()
     {
@@ -136,7 +136,7 @@ public class PosEditor : EditorBase
 
         try
         {
-            Pos? pos = _posRadioGroup!.SelectedItem switch
+            Pos? pos = _posOptionSelector!.Value switch
                        {
                            0 => Pos.Absolute (_value),
                            1 => Pos.Align (Alignment.Start),
@@ -160,7 +160,7 @@ public class PosEditor : EditorBase
         }
         catch (Exception e)
         {
-            MessageBox.ErrorQuery ("Exception", e.Message, "Ok");
+            MessageBox.ErrorQuery (App, "Exception", e.Message, "Ok");
         }
     }
 }

+ 9 - 10
Examples/UICatalog/Scenarios/EditorsAndHelpers/ViewPropertiesEditor.cs

@@ -6,7 +6,7 @@ public class ViewPropertiesEditor : EditorBase
 {
     private CheckBox? _canFocusCheckBox;
     private CheckBox? _enabledCheckBox;
-    private RadioGroup? _orientation;
+    private OptionSelector<Orientation>? _orientationOptionSelector;
     private TextView? _text;
 
     /// <inheritdoc/>
@@ -48,24 +48,23 @@ public class ViewPropertiesEditor : EditorBase
 
         Label label = new () { X = Pos.Right (_enabledCheckBox) + 1, Y = Pos.Top (_enabledCheckBox), Text = "Orientation:" };
 
-        _orientation = new ()
+        _orientationOptionSelector = new ()
         {
             X = Pos.Right (label) + 1,
             Y = Pos.Top (label),
-            RadioLabels = new [] { "Horizontal", "Vertical" },
             Orientation = Orientation.Horizontal
         };
 
-        _orientation.SelectedItemChanged += (s, selected) =>
+        _orientationOptionSelector.ValueChanged += (s, selected) =>
                                             {
                                                 if (ViewToEdit is IOrientation orientatedView)
                                                 {
-                                                    orientatedView.Orientation = (Orientation)_orientation.SelectedItem!;
+                                                    orientatedView.Orientation = _orientationOptionSelector.Value!.Value;
                                                 }
                                             };
-        Add (label, _orientation);
+        Add (label, _orientationOptionSelector);
 
-        label = new () { X = 0, Y = Pos.Bottom (_orientation), Text = "Text:" };
+        label = new () { X = 0, Y = Pos.Bottom (_orientationOptionSelector), Text = "Text:" };
 
         _text = new ()
         {
@@ -114,12 +113,12 @@ public class ViewPropertiesEditor : EditorBase
 
             if (ViewToEdit is IOrientation orientatedView)
             {
-                _orientation!.SelectedItem = (int)orientatedView.Orientation;
-                _orientation.Enabled = true;
+                _orientationOptionSelector!.Value = orientatedView.Orientation;
+                _orientationOptionSelector.Enabled = true;
             }
             else
             {
-                _orientation!.Enabled = false;
+                _orientationOptionSelector!.Enabled = false;
             }
         }
     }

+ 134 - 134
Examples/UICatalog/Scenarios/FileDialogExamples.cs

@@ -1,8 +1,4 @@
-using System;
-using System.IO;
-using System.IO.Abstractions;
-using System.Linq;
-using System.Text;
+using System.IO.Abstractions;
 
 namespace UICatalog.Scenarios;
 
@@ -20,10 +16,10 @@ public class FileDialogExamples : Scenario
     private CheckBox _cbMustExist;
     private CheckBox _cbShowTreeBranchLines;
     private CheckBox _cbUseColors;
-    private RadioGroup _rgAllowedTypes;
-    private RadioGroup _rgCaption;
-    private RadioGroup _rgIcons;
-    private RadioGroup _rgOpenMode;
+    private OptionSelector _osAllowedTypes;
+    private OptionSelector _osCaption;
+    private OptionSelector _osIcons;
+    private OptionSelector _osOpenMode;
     private TextField _tbCancelButton;
     private TextField _tbOkButton;
 
@@ -34,28 +30,29 @@ public class FileDialogExamples : Scenario
         var x = 1;
         var win = new Window { Title = GetQuitKeyAndName () };
 
-        _cbMustExist = new CheckBox { CheckedState = CheckState.Checked, Y = y++, X = x, Text = "Must E_xist" };
+        _cbMustExist = new () { CheckedState = CheckState.Checked, Y = y++, X = x, Text = "Must E_xist" };
         win.Add (_cbMustExist);
 
-        _cbUseColors = new CheckBox { CheckedState = FileDialogStyle.DefaultUseColors ? CheckState.Checked : CheckState.UnChecked, Y = y++, X = x, Text = "_Use Colors" };
+        _cbUseColors = new ()
+            { CheckedState = FileDialogStyle.DefaultUseColors ? CheckState.Checked : CheckState.UnChecked, Y = y++, X = x, Text = "_Use Colors" };
         win.Add (_cbUseColors);
 
-        _cbCaseSensitive = new CheckBox { CheckedState = CheckState.UnChecked, Y = y++, X = x, Text = "_Case Sensitive Search" };
+        _cbCaseSensitive = new () { CheckedState = CheckState.UnChecked, Y = y++, X = x, Text = "_Case Sensitive Search" };
         win.Add (_cbCaseSensitive);
 
-        _cbAllowMultipleSelection = new CheckBox { CheckedState = CheckState.UnChecked, Y = y++, X = x, Text = "_Multiple" };
+        _cbAllowMultipleSelection = new () { CheckedState = CheckState.UnChecked, Y = y++, X = x, Text = "_Multiple" };
         win.Add (_cbAllowMultipleSelection);
 
-        _cbShowTreeBranchLines = new CheckBox { CheckedState = CheckState.Checked, Y = y++, X = x, Text = "Tree Branch _Lines" };
+        _cbShowTreeBranchLines = new () { CheckedState = CheckState.Checked, Y = y++, X = x, Text = "Tree Branch _Lines" };
         win.Add (_cbShowTreeBranchLines);
 
-        _cbAlwaysTableShowHeaders = new CheckBox { CheckedState = CheckState.Checked, Y = y++, X = x, Text = "Always Show _Headers" };
+        _cbAlwaysTableShowHeaders = new () { CheckedState = CheckState.Checked, Y = y++, X = x, Text = "Always Show _Headers" };
         win.Add (_cbAlwaysTableShowHeaders);
 
-        _cbDrivesOnlyInTree = new CheckBox { CheckedState = CheckState.UnChecked, Y = y++, X = x, Text = "Only Show _Drives" };
+        _cbDrivesOnlyInTree = new () { CheckedState = CheckState.UnChecked, Y = y++, X = x, Text = "Only Show _Drives" };
         win.Add (_cbDrivesOnlyInTree);
 
-        _cbPreserveFilenameOnDirectoryChanges = new CheckBox { CheckedState = CheckState.UnChecked, Y = y++, X = x, Text = "Preserve Filename" };
+        _cbPreserveFilenameOnDirectoryChanges = new () { CheckedState = CheckState.UnChecked, Y = y++, X = x, Text = "Preserve Filename" };
         win.Add (_cbPreserveFilenameOnDirectoryChanges);
 
         y = 0;
@@ -66,9 +63,9 @@ public class FileDialogExamples : Scenario
                 );
         win.Add (new Label { X = x++, Y = y++, Text = "Caption" });
 
-        _rgCaption = new RadioGroup { X = x, Y = y };
-        _rgCaption.RadioLabels = new [] { "_Ok", "O_pen", "_Save" };
-        win.Add (_rgCaption);
+        _osCaption = new () { X = x, Y = y };
+        _osCaption.Labels = ["_Ok", "O_pen", "_Save"];
+        win.Add (_osCaption);
 
         y = 0;
         x = 34;
@@ -78,9 +75,9 @@ public class FileDialogExamples : Scenario
                 );
         win.Add (new Label { X = x++, Y = y++, Text = "OpenMode" });
 
-        _rgOpenMode = new RadioGroup { X = x, Y = y };
-        _rgOpenMode.RadioLabels = new [] { "_File", "D_irectory", "_Mixed" };
-        win.Add (_rgOpenMode);
+        _osOpenMode = new () { X = x, Y = y };
+        _osOpenMode.Labels = ["_File", "D_irectory", "_Mixed"];
+        win.Add (_osOpenMode);
 
         y = 0;
         x = 48;
@@ -90,9 +87,9 @@ public class FileDialogExamples : Scenario
                 );
         win.Add (new Label { X = x++, Y = y++, Text = "Icons" });
 
-        _rgIcons = new RadioGroup { X = x, Y = y };
-        _rgIcons.RadioLabels = new [] { "_None", "_Unicode", "Nerd_*" };
-        win.Add (_rgIcons);
+        _osIcons = new () { X = x, Y = y };
+        _osIcons.Labels = ["_None", "_Unicode", "Nerd_*"];
+        win.Add (_osIcons);
 
         win.Add (new Label { Y = Pos.AnchorEnd (2), Text = "* Requires installing Nerd fonts" });
         win.Add (new Label { Y = Pos.AnchorEnd (1), Text = "  (see: https://github.com/devblackops/Terminal-Icons)" });
@@ -105,9 +102,9 @@ public class FileDialogExamples : Scenario
                 );
         win.Add (new Label { X = x++, Y = y++, Text = "Allowed" });
 
-        _rgAllowedTypes = new RadioGroup { X = x, Y = y };
-        _rgAllowedTypes.RadioLabels = new [] { "An_y", "Cs_v (Recommended)", "Csv (S_trict)" };
-        win.Add (_rgAllowedTypes);
+        _osAllowedTypes = new () { X = x, Y = y };
+        _osAllowedTypes.Labels = ["An_y", "Cs_v (Recommended)", "Csv (S_trict)"];
+        win.Add (_osAllowedTypes);
 
         y = 5;
         x = 45;
@@ -118,31 +115,31 @@ public class FileDialogExamples : Scenario
         win.Add (new Label { X = x++, Y = y++, Text = "Buttons" });
 
         win.Add (new Label { X = x, Y = y++, Text = "O_k Text:" });
-        _tbOkButton = new TextField { X = x, Y = y++, Width = 12 };
+        _tbOkButton = new () { X = x, Y = y++, Width = 12 };
         win.Add (_tbOkButton);
         win.Add (new Label { X = x, Y = y++, Text = "_Cancel Text:" });
-        _tbCancelButton = new TextField { X = x, Y = y++, Width = 12 };
+        _tbCancelButton = new () { X = x, Y = y++, Width = 12 };
         win.Add (_tbCancelButton);
-        _cbFlipButtonOrder = new CheckBox { X = x, Y = y++, Text = "Flip Ord_er" };
+        _cbFlipButtonOrder = new () { X = x, Y = y++, Text = "Flip Ord_er" };
         win.Add (_cbFlipButtonOrder);
 
         var btn = new Button { X = 1, Y = 9, IsDefault = true, Text = "Run Dialog" };
 
         win.Accepting += (s, e) =>
-                        {
-                            try
-                            {
-                                CreateDialog ();
-                            }
-                            catch (Exception ex)
-                            {
-                                MessageBox.ErrorQuery ("Error", ex.ToString (), "_Ok");
-                            }
-                            finally
-                            {
-                                e.Handled = true;
-                            }
-                        };
+                         {
+                             try
+                             {
+                                 CreateDialog ();
+                             }
+                             catch (Exception ex)
+                             {
+                                 MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", ex.ToString (), "_Ok");
+                             }
+                             finally
+                             {
+                                 e.Handled = true;
+                             }
+                         };
         win.Add (btn);
 
         Application.Run (win);
@@ -156,7 +153,7 @@ public class FileDialogExamples : Scenario
         {
             if (File.Exists (e.Dialog.Path))
             {
-                int result = MessageBox.Query ("Overwrite?", "File already exists", "_Yes", "_No");
+                int? result = MessageBox.Query (ApplicationImpl.Instance, "Overwrite?", "File already exists", "_Yes", "_No");
                 e.Cancel = result == 1;
             }
         }
@@ -164,112 +161,115 @@ public class FileDialogExamples : Scenario
 
     private void CreateDialog ()
     {
-        var fd = new FileDialog
+        if (_osOpenMode.Value is { })
         {
-            OpenMode = Enum.Parse<OpenMode> (
-                                             _rgOpenMode.RadioLabels
-                                                        .Select (l => TextFormatter.FindHotKey (l, _rgOpenMode.HotKeySpecifier, out int hotPos, out Key _)
-
-                                                                          // Remove the hotkey specifier at the found position
-                                                                          ? TextFormatter.RemoveHotKeySpecifier (l, hotPos, _rgOpenMode.HotKeySpecifier)
-
-                                                                          // No hotkey found, return the label as is
-                                                                          : l)
-                                                        .ToArray () [_rgOpenMode.SelectedItem]
-                                            ),
-            MustExist = _cbMustExist.CheckedState == CheckState.Checked,
-            AllowsMultipleSelection = _cbAllowMultipleSelection.CheckedState == CheckState.Checked
-        };
+            var fd = new FileDialog
+            {
+                OpenMode = Enum.Parse<OpenMode> (
+                                                 _osOpenMode.Labels
+                                                            .Select (l => TextFormatter.FindHotKey (l, _osOpenMode.HotKeySpecifier, out int hotPos, out Key _)
+
+                                                                              // Remove the hotkey specifier at the found position
+                                                                              ? TextFormatter.RemoveHotKeySpecifier (l, hotPos, _osOpenMode.HotKeySpecifier)
+
+                                                                              // No hotkey found, return the label as is
+                                                                              : l)
+                                                            .ToArray () [_osOpenMode.Value.Value]
+                                                ),
+                MustExist = _cbMustExist.CheckedState == CheckState.Checked,
+                AllowsMultipleSelection = _cbAllowMultipleSelection.CheckedState == CheckState.Checked
+            };
+
+            fd.Style.OkButtonText =
+                _osCaption.Labels.Select (l => TextFormatter.RemoveHotKeySpecifier (l, 0, _osCaption.HotKeySpecifier)).ToArray ()
+                    [_osCaption.Value!.Value];
+
+            // If Save style dialog then give them an overwrite prompt
+            if (_osCaption.Value == 2)
+            {
+                fd.FilesSelected += ConfirmOverwrite;
+            }
 
-        fd.Style.OkButtonText = _rgCaption.RadioLabels.Select (l => TextFormatter.RemoveHotKeySpecifier(l, 0, _rgCaption.HotKeySpecifier)).ToArray() [_rgCaption.SelectedItem];
+            fd.Style.IconProvider.UseUnicodeCharacters = _osIcons.Value == 1;
+            fd.Style.IconProvider.UseNerdIcons = _osIcons.Value == 2;
 
-        // If Save style dialog then give them an overwrite prompt
-        if (_rgCaption.SelectedItem == 2)
-        {
-            fd.FilesSelected += ConfirmOverwrite;
-        }
-
-        fd.Style.IconProvider.UseUnicodeCharacters = _rgIcons.SelectedItem == 1;
-        fd.Style.IconProvider.UseNerdIcons = _rgIcons.SelectedItem == 2;
+            if (_cbCaseSensitive.CheckedState == CheckState.Checked)
+            {
+                fd.SearchMatcher = new CaseSensitiveSearchMatcher ();
+            }
 
-        if (_cbCaseSensitive.CheckedState == CheckState.Checked)
-        {
-            fd.SearchMatcher = new CaseSensitiveSearchMatcher ();
-        }
+            fd.Style.UseColors = _cbUseColors.CheckedState == CheckState.Checked;
 
-        fd.Style.UseColors = _cbUseColors.CheckedState == CheckState.Checked;
+            fd.Style.TreeStyle.ShowBranchLines = _cbShowTreeBranchLines.CheckedState == CheckState.Checked;
+            fd.Style.TableStyle.AlwaysShowHeaders = _cbAlwaysTableShowHeaders.CheckedState == CheckState.Checked;
 
-        fd.Style.TreeStyle.ShowBranchLines = _cbShowTreeBranchLines.CheckedState == CheckState.Checked;
-        fd.Style.TableStyle.AlwaysShowHeaders = _cbAlwaysTableShowHeaders.CheckedState == CheckState.Checked;
+            IDirectoryInfoFactory dirInfoFactory = new FileSystem ().DirectoryInfo;
 
-        IDirectoryInfoFactory dirInfoFactory = new FileSystem ().DirectoryInfo;
+            if (_cbDrivesOnlyInTree.CheckedState == CheckState.Checked)
+            {
+                fd.Style.TreeRootGetter = () => { return Environment.GetLogicalDrives ().ToDictionary (dirInfoFactory.New, k => k); };
+            }
 
-        if (_cbDrivesOnlyInTree.CheckedState == CheckState.Checked)
-        {
-            fd.Style.TreeRootGetter = () => { return Environment.GetLogicalDrives ().ToDictionary (dirInfoFactory.New, k => k); };
-        }
+            fd.Style.PreserveFilenameOnDirectoryChanges = _cbPreserveFilenameOnDirectoryChanges.CheckedState == CheckState.Checked;
 
-        fd.Style.PreserveFilenameOnDirectoryChanges = _cbPreserveFilenameOnDirectoryChanges.CheckedState == CheckState.Checked;
-        
+            if (_osAllowedTypes.Value > 0)
+            {
+                fd.AllowedTypes.Add (new AllowedType ("Data File", ".csv", ".tsv"));
 
-        if (_rgAllowedTypes.SelectedItem > 0)
-        {
-            fd.AllowedTypes.Add (new AllowedType ("Data File", ".csv", ".tsv"));
+                if (_osAllowedTypes.Value == 1)
+                {
+                    fd.AllowedTypes.Insert (1, new AllowedTypeAny ());
+                }
+            }
 
-            if (_rgAllowedTypes.SelectedItem == 1)
+            if (!string.IsNullOrWhiteSpace (_tbOkButton.Text))
             {
-                fd.AllowedTypes.Insert (1, new AllowedTypeAny ());
+                fd.Style.OkButtonText = _tbOkButton.Text;
             }
-        }
 
-        if (!string.IsNullOrWhiteSpace (_tbOkButton.Text))
-        {
-            fd.Style.OkButtonText = _tbOkButton.Text;
-        }
-
-        if (!string.IsNullOrWhiteSpace (_tbCancelButton.Text))
-        {
-            fd.Style.CancelButtonText = _tbCancelButton.Text;
-        }
-
-        if (_cbFlipButtonOrder.CheckedState == CheckState.Checked)
-        {
-            fd.Style.FlipOkCancelButtonLayoutOrder = true;
-        }
+            if (!string.IsNullOrWhiteSpace (_tbCancelButton.Text))
+            {
+                fd.Style.CancelButtonText = _tbCancelButton.Text;
+            }
 
-        Application.Run (fd);
+            if (_cbFlipButtonOrder.CheckedState == CheckState.Checked)
+            {
+                fd.Style.FlipOkCancelButtonLayoutOrder = true;
+            }
 
-        var canceled = fd.Canceled;
-        var multiSelected = fd.MultiSelected;
-        var path = fd.Path;
+            Application.Run (fd);
 
-        // This needs to be disposed before opening other toplevel
-        fd.Dispose ();
+            bool canceled = fd.Canceled;
+            IReadOnlyList<string> multiSelected = fd.MultiSelected;
+            string path = fd.Path;
 
-        if (canceled)
-        {
-            MessageBox.Query (
-                              "Canceled",
-                              "You canceled navigation and did not pick anything",
-                              "Ok"
-                             );
+            // This needs to be disposed before opening other runnable
+            fd.Dispose ();
 
-        }
-        else if (_cbAllowMultipleSelection.CheckedState == CheckState.Checked)
-        {
-            MessageBox.Query (
-                              "Chosen!",
-                              "You chose:" + Environment.NewLine + string.Join (Environment.NewLine, multiSelected.Select (m => m)),
-                              "Ok"
-                             );
-        }
-        else
-        {
-            MessageBox.Query (
-                              "Chosen!",
-                              "You chose:" + Environment.NewLine + path,
-                              "Ok"
-                             );
+            if (canceled)
+            {
+                MessageBox.Query (ApplicationImpl.Instance,
+                                  "Canceled",
+                                  "You canceled navigation and did not pick anything",
+                                  "Ok"
+                                 );
+            }
+            else if (_cbAllowMultipleSelection.CheckedState == CheckState.Checked)
+            {
+                MessageBox.Query (ApplicationImpl.Instance,
+                                  "Chosen!",
+                                  "You chose:" + Environment.NewLine + string.Join (Environment.NewLine, multiSelected.Select (m => m)),
+                                  "Ok"
+                                 );
+            }
+            else
+            {
+                MessageBox.Query (ApplicationImpl.Instance,
+                                  "Chosen!",
+                                  "You chose:" + Environment.NewLine + path,
+                                  "Ok"
+                                 );
+            }
         }
     }
 

+ 1 - 1
Examples/UICatalog/Scenarios/Generic.cs

@@ -29,7 +29,7 @@ public sealed class Generic : Scenario
                             {
                                 // When Accepting is handled, set e.Handled to true to prevent further processing.
                                 e.Handled = true;
-                                MessageBox.ErrorQuery ("Error", "You pressed the button!", "_Ok");
+                                MessageBox.ErrorQuery (ApplicationImpl.Instance, "Error", "You pressed the button!", "_Ok");
                             };
 
         appWindow.Add (button);

+ 303 - 343
Examples/UICatalog/Scenarios/GraphViewExample.cs

@@ -1,9 +1,6 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.Linq;
+#nullable enable
+
 using System.Text;
-using Application = Terminal.Gui.App.Application;
 
 namespace UICatalog.Scenarios;
 
@@ -13,144 +10,53 @@ namespace UICatalog.Scenarios;
 public class GraphViewExample : Scenario
 {
     private readonly Thickness _thickness = new (1, 1, 1, 1);
-    private TextView _about;
+    private TextView? _about;
     private int _currentGraph;
-    private Action [] _graphs;
-    private GraphView _graphView;
-    private MenuItem _miDiags;
-    private MenuItem _miShowBorder;
+    private Action []? _graphs;
+    private GraphView? _graphView;
+    private CheckBox? _diagCheckBox;
+    private CheckBox? _showBorderCheckBox;
     private ViewDiagnosticFlags _viewDiagnostics;
 
     public override void Main ()
     {
         Application.Init ();
-        Toplevel app = new ();
-
-        _graphs = new []
-        {
-            () => SetupPeriodicTableScatterPlot (), //0
-            () => SetupLifeExpectancyBarGraph (true), //1
-            () => SetupLifeExpectancyBarGraph (false), //2
-            () => SetupPopulationPyramid (), //3
-            () => SetupLineGraph (), //4
-            () => SetupSineWave (), //5
-            () => SetupDisco (), //6
-            () => MultiBarGraph () //7
-        };
 
-        var menu = new MenuBar
+        Window app = new ()
         {
-            Menus =
-            [
-                new (
-                     "_File",
-                     new MenuItem []
-                     {
-                         new (
-                              "Scatter _Plot",
-                              "",
-                              () => _graphs [_currentGraph =
-                                                 0] ()
-                             ),
-                         new (
-                              "_V Bar Graph",
-                              "",
-                              () => _graphs [_currentGraph =
-                                                 1] ()
-                             ),
-                         new (
-                              "_H Bar Graph",
-                              "",
-                              () => _graphs [_currentGraph =
-                                                 2] ()
-                             ),
-                         new (
-                              "P_opulation Pyramid",
-                              "",
-                              () => _graphs [_currentGraph =
-                                                 3] ()
-                             ),
-                         new (
-                              "_Line Graph",
-                              "",
-                              () => _graphs [_currentGraph =
-                                                 4] ()
-                             ),
-                         new (
-                              "Sine _Wave",
-                              "",
-                              () => _graphs [_currentGraph =
-                                                 5] ()
-                             ),
-                         new (
-                              "Silent _Disco",
-                              "",
-                              () => _graphs [_currentGraph =
-                                                 6] ()
-                             ),
-                         new (
-                              "_Multi Bar Graph",
-                              "",
-                              () => _graphs [_currentGraph =
-                                                 7] ()
-                             ),
-                         new ("_Quit", "", () => Quit ())
-                     }
-                    ),
-                new (
-                     "_View",
-                     new []
-                     {
-                         new ("Zoom _In", "", () => Zoom (0.5f)),
-                         new ("Zoom _Out", "", () => Zoom (2f)),
-                         new ("MarginLeft++", "", () => Margin (true, true)),
-                         new ("MarginLeft--", "", () => Margin (true, false)),
-                         new ("MarginBottom++", "", () => Margin (false, true)),
-                         new ("MarginBottom--", "", () => Margin (false, false)),
-                         _miShowBorder = new (
-                                              "_Enable Margin, Border, and Padding",
-                                              "",
-                                              () => ShowBorder ()
-                                             )
-                         {
-                             Checked = true,
-                             CheckType = MenuItemCheckStyle
-                                 .Checked
-                         },
-                         _miDiags = new (
-                                         "_Diagnostics",
-                                         "",
-                                         () => ToggleDiagnostics ()
-                                        )
-                         {
-                             Checked = View.Diagnostics
-                                       == (ViewDiagnosticFlags
-                                               .Thickness
-                                           | ViewDiagnosticFlags
-                                               .Ruler),
-                             CheckType = MenuItemCheckStyle.Checked
-                         }
-                     }
-                    )
-            ]
+            BorderStyle = LineStyle.None
         };
-        app.Add (menu);
 
+        _graphs =
+        [
+            SetupPeriodicTableScatterPlot,
+            () => SetupLifeExpectancyBarGraph (true),
+            () => SetupLifeExpectancyBarGraph (false),
+            SetupPopulationPyramid,
+            SetupLineGraph,
+            SetupSineWave,
+            SetupDisco,
+            MultiBarGraph
+        ];
+
+        // MenuBar
+        MenuBar menu = new ();
+
+        // GraphView
         _graphView = new ()
         {
             X = 0,
-            Y = 1,
+            Y = Pos.Bottom (menu),
             Width = Dim.Percent (70),
             Height = Dim.Fill (1),
             BorderStyle = LineStyle.Single
         };
-        _graphView.Border.Thickness = _thickness;
-        _graphView.Margin.Thickness = _thickness;
-        _graphView.Padding.Thickness = _thickness;
+        _graphView.Border!.Thickness = _thickness;
+        _graphView.Margin!.Thickness = _thickness;
+        _graphView.Padding!.Thickness = _thickness;
 
-        app.Add (_graphView);
-
-        var frameRight = new FrameView
+        // About TextView
+        FrameView frameRight = new ()
         {
             X = Pos.Right (_graphView),
             Y = Pos.Top (_graphView),
@@ -159,23 +65,24 @@ public class GraphViewExample : Scenario
             Title = "About"
         };
 
-        frameRight.Add (
-                        _about = new () { Width = Dim.Fill (), Height = Dim.Fill (), ReadOnly = true }
-                       );
-
-        app.Add (frameRight);
-
-        var statusBar = new StatusBar (
-                                       new Shortcut []
-                                       {
-                                           new (Key.G.WithCtrl, "Next Graph", () => _graphs [_currentGraph++ % _graphs.Length] ()),
-                                           new (Key.PageUp, "Zoom In", () => Zoom (0.5f)),
-                                           new (Key.PageDown, "Zoom Out", () => Zoom (2f))
-                                       }
-                                      );
-        app.Add (statusBar);
+        _about = new ()
+        {
+            Width = Dim.Fill (),
+            Height = Dim.Fill (),
+            ReadOnly = true
+        };
+        frameRight.Add (_about);
+
+        // StatusBar
+        StatusBar statusBar = new (
+                                   [
+                                       new (Key.G.WithCtrl, "Next Graph", () => _graphs! [_currentGraph++ % _graphs.Length] ()),
+                                       new (Key.PageUp, "Zoom In", () => Zoom (0.5f)),
+                                       new (Key.PageDown, "Zoom Out", () => Zoom (2f))
+                                   ]
+                                  );
 
-        var diagShortcut = new Shortcut
+        Shortcut? diagShortcut = new ()
         {
             Key = Key.F10,
             CommandView = new CheckBox
@@ -184,7 +91,128 @@ public class GraphViewExample : Scenario
                 CanFocus = false
             }
         };
-        statusBar.Add (diagShortcut).Accepting += DiagShortcut_Accept;
+        
+        statusBar.Add (diagShortcut);
+        diagShortcut.Accepting += DiagShortcut_Accept;
+
+        // Menu setup
+        _showBorderCheckBox = new ()
+        {
+            Title = "_Enable Margin, Border, and Padding",
+            CheckedState = CheckState.Checked
+        };
+        _showBorderCheckBox.CheckedStateChanged += (s, e) => ShowBorder ();
+
+        _diagCheckBox = new ()
+        {
+            Title = "_Diagnostics",
+            CheckedState = View.Diagnostics == (ViewDiagnosticFlags.Thickness | ViewDiagnosticFlags.Ruler)
+                               ? CheckState.Checked
+                               : CheckState.UnChecked
+        };
+        _diagCheckBox.CheckedStateChanged += (s, e) => ToggleDiagnostics ();
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_File",
+                                   [
+                                       new MenuItem
+                                       {
+                                           Title = "Scatter _Plot",
+                                           Action = () => _graphs [_currentGraph = 0] ()
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_V Bar Graph",
+                                           Action = () => _graphs [_currentGraph = 1] ()
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_H Bar Graph",
+                                           Action = () => _graphs [_currentGraph = 2] ()
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "P_opulation Pyramid",
+                                           Action = () => _graphs [_currentGraph = 3] ()
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Line Graph",
+                                           Action = () => _graphs [_currentGraph = 4] ()
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "Sine _Wave",
+                                           Action = () => _graphs [_currentGraph = 5] ()
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "Silent _Disco",
+                                           Action = () => _graphs [_currentGraph = 6] ()
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Multi Bar Graph",
+                                           Action = () => _graphs [_currentGraph = 7] ()
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Quit",
+                                           Action = Quit
+                                       }
+                                   ]
+                                  )
+                 );
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_View",
+                                   [
+                                       new MenuItem
+                                       {
+                                           Title = "Zoom _In",
+                                           Action = () => Zoom (0.5f)
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "Zoom _Out",
+                                           Action = () => Zoom (2f)
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "MarginLeft++",
+                                           Action = () => Margin (true, true)
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "MarginLeft--",
+                                           Action = () => Margin (true, false)
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "MarginBottom++",
+                                           Action = () => Margin (false, true)
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "MarginBottom--",
+                                           Action = () => Margin (false, false)
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _showBorderCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _diagCheckBox
+                                       }
+                                   ]
+                                  )
+                 );
+
+        // Add views in order of visual appearance
+        app.Add (menu, _graphView, frameRight, statusBar);
 
         _graphs [_currentGraph++ % _graphs.Length] ();
 
@@ -195,29 +223,31 @@ public class GraphViewExample : Scenario
         Application.Shutdown ();
     }
 
-    private void DiagShortcut_Accept (object sender, CommandEventArgs e)
+    private void DiagShortcut_Accept (object? sender, CommandEventArgs e)
     {
         ToggleDiagnostics ();
 
         if (sender is Shortcut shortcut && shortcut.CommandView is CheckBox checkBox)
         {
-            checkBox.CheckedState = _miDiags.Checked ?? false ? CheckState.Checked : CheckState.UnChecked;
+            checkBox.CheckedState = _diagCheckBox?.CheckedState ?? CheckState.UnChecked;
         }
     }
 
     private void ToggleDiagnostics ()
     {
-        _miDiags.Checked = !_miDiags.Checked;
-
-        View.Diagnostics = _miDiags.Checked == true
-                               ? ViewDiagnosticFlags.Thickness
-                                 | ViewDiagnosticFlags.Ruler
+        View.Diagnostics = _diagCheckBox?.CheckedState == CheckState.Checked
+                               ? ViewDiagnosticFlags.Thickness | ViewDiagnosticFlags.Ruler
                                : ViewDiagnosticFlags.Off;
         Application.LayoutAndDraw ();
     }
 
     private void Margin (bool left, bool increase)
     {
+        if (_graphView is null)
+        {
+            return;
+        }
+
         if (left)
         {
             _graphView.MarginLeft = (uint)Math.Max (0, _graphView.MarginLeft + (increase ? 1 : -1));
@@ -232,6 +262,11 @@ public class GraphViewExample : Scenario
 
     private void MultiBarGraph ()
     {
+        if (_graphView is null || _about is null)
+        {
+            return;
+        }
+
         _graphView.Reset ();
 
         _graphView.Title = "Multi Bar";
@@ -241,14 +276,14 @@ public class GraphViewExample : Scenario
         Color fore = _graphView.GetAttributeForRole (VisualRole.Normal).Foreground == Color.Black
                          ? Color.White
                          : _graphView.GetAttributeForRole (VisualRole.Normal).Foreground;
-        var black = new Attribute (fore, Color.Black);
-        var cyan = new Attribute (Color.BrightCyan, Color.Black);
-        var magenta = new Attribute (Color.BrightMagenta, Color.Black);
-        var red = new Attribute (Color.BrightRed, Color.Black);
+        Attribute black = new (fore, Color.Black);
+        Attribute cyan = new (Color.BrightCyan, Color.Black);
+        Attribute magenta = new (Color.BrightMagenta, Color.Black);
+        Attribute red = new (Color.BrightRed, Color.Black);
 
         _graphView.GraphColor = black;
 
-        var series = new MultiBarSeries (3, 1, 0.25f, new [] { magenta, cyan, red });
+        MultiBarSeries series = new (3, 1, 0.25f, [magenta, cyan, red]);
 
         Rune stiple = Glyphs.Stipple;
 
@@ -277,20 +312,20 @@ public class GraphViewExample : Scenario
 
         _graphView.AxisY.Minimum = 0;
 
-        var legend = new LegendAnnotation (new (_graphView.Viewport.Width - 20, 0, 20, 5));
+        LegendAnnotation legend = new (new (_graphView.Viewport.Width - 20, 0, 20, 5));
 
         legend.AddEntry (
-                         new (stiple, series.SubSeries.ElementAt (0).OverrideBarColor),
+                         new (stiple, series.SubSeries.ElementAt (0).OverrideBarColor ?? black),
                          "Lower Third"
                         );
 
         legend.AddEntry (
-                         new (stiple, series.SubSeries.ElementAt (1).OverrideBarColor),
+                         new (stiple, series.SubSeries.ElementAt (1).OverrideBarColor ?? cyan),
                          "Middle Third"
                         );
 
         legend.AddEntry (
-                         new (stiple, series.SubSeries.ElementAt (2).OverrideBarColor),
+                         new (stiple, series.SubSeries.ElementAt (2).OverrideBarColor ?? red),
                          "Upper Third"
                         );
         _graphView.Annotations.Add (legend);
@@ -300,6 +335,11 @@ public class GraphViewExample : Scenario
 
     private void SetupDisco ()
     {
+        if (_graphView is null || _about is null)
+        {
+            return;
+        }
+
         _graphView.Reset ();
 
         _graphView.Title = "Graphic Equalizer";
@@ -308,11 +348,11 @@ public class GraphViewExample : Scenario
 
         _graphView.GraphColor = new Attribute (Color.White, Color.Black);
 
-        var stiple = new GraphCellToRender ((Rune)'\u2593');
+        GraphCellToRender stiple = new ((Rune)'\u2593');
 
-        var r = new Random ();
-        var series = new DiscoBarSeries ();
-        List<BarSeriesBar> bars = new ();
+        Random r = new ();
+        DiscoBarSeries series = new ();
+        List<BarSeriesBar> bars = [];
 
         Func<bool> genSample = () =>
                                {
@@ -323,16 +363,13 @@ public class GraphViewExample : Scenario
                                    {
                                        bars.Add (
                                                  new (null, stiple, r.Next (0, 100))
-                                                 {
-                                                     //ColorGetter = colorDelegate
-                                                 }
                                                 );
                                    }
 
-                                   _graphView.SetNeedsDraw ();
+                                   _graphView?.SetNeedsDraw ();
 
                                    // while the equaliser is showing
-                                   return _graphView.Series.Contains (series);
+                                   return _graphView is { } && _graphView.Series.Contains (series);
                                };
 
         Application.AddTimeout (TimeSpan.FromMilliseconds (250), genSample);
@@ -351,120 +388,45 @@ public class GraphViewExample : Scenario
 
         _graphView.SetNeedsDraw ();
     }
-    /*
-    Country,Both,Male,Female
-
-"Switzerland",83.4,81.8,85.1
-"South Korea",83.3,80.3,86.1
-"Singapore",83.2,81,85.5
-"Spain",83.2,80.7,85.7
-"Cyprus",83.1,81.1,85.1
-"Australia",83,81.3,84.8
-"Italy",83,80.9,84.9
-"Norway",83,81.2,84.7
-"Israel",82.6,80.8,84.4
-"France",82.5,79.8,85.1
-"Luxembourg",82.4,80.6,84.2
-"Sweden",82.4,80.8,84
-"Iceland",82.3,80.8,83.9
-"Canada",82.2,80.4,84.1
-"New Zealand",82,80.4,83.5
-"Malta,81.9",79.9,83.8
-"Ireland",81.8,80.2,83.5
-"Netherlands",81.8,80.4,83.1
-"Germany",81.7,78.7,84.8
-"Austria",81.6,79.4,83.8
-"Finland",81.6,79.2,84
-"Portugal",81.6,78.6,84.4
-"Belgium",81.4,79.3,83.5
-"United Kingdom",81.4,79.8,83
-"Denmark",81.3,79.6,83
-"Slovenia",81.3,78.6,84.1
-"Greece",81.1,78.6,83.6
-"Kuwait",81,79.3,83.9
-"Costa Rica",80.8,78.3,83.4*/
 
     private void SetupLifeExpectancyBarGraph (bool verticalBars)
     {
+        if (_graphView is null || _about is null)
+        {
+            return;
+        }
+
         _graphView.Reset ();
 
         _graphView.Title = $"Life Expectancy - {(verticalBars ? "Vertical" : "Horizontal")}";
 
         _about.Text = "This graph shows the life expectancy at birth of a range of countries";
 
-        var softStiple = new GraphCellToRender ((Rune)'\u2591');
-        var mediumStiple = new GraphCellToRender ((Rune)'\u2592');
+        GraphCellToRender softStiple = new ((Rune)'\u2591');
+        GraphCellToRender mediumStiple = new ((Rune)'\u2592');
 
-        var barSeries = new BarSeries
+        BarSeries barSeries = new ()
         {
-            Bars = new ()
-            {
+            Bars =
+            [
                 new ("Switzerland", softStiple, 83.4f),
-                new (
-                     "South Korea",
-                     !verticalBars
-                         ? mediumStiple
-                         : softStiple,
-                     83.3f
-                    ),
+                new ("South Korea", !verticalBars ? mediumStiple : softStiple, 83.3f),
                 new ("Singapore", softStiple, 83.2f),
-                new (
-                     "Spain",
-                     !verticalBars
-                         ? mediumStiple
-                         : softStiple,
-                     83.2f
-                    ),
+                new ("Spain", !verticalBars ? mediumStiple : softStiple, 83.2f),
                 new ("Cyprus", softStiple, 83.1f),
-                new (
-                     "Australia",
-                     !verticalBars
-                         ? mediumStiple
-                         : softStiple,
-                     83
-                    ),
+                new ("Australia", !verticalBars ? mediumStiple : softStiple, 83),
                 new ("Italy", softStiple, 83),
-                new (
-                     "Norway",
-                     !verticalBars
-                         ? mediumStiple
-                         : softStiple,
-                     83
-                    ),
+                new ("Norway", !verticalBars ? mediumStiple : softStiple, 83),
                 new ("Israel", softStiple, 82.6f),
-                new (
-                     "France",
-                     !verticalBars
-                         ? mediumStiple
-                         : softStiple,
-                     82.5f
-                    ),
+                new ("France", !verticalBars ? mediumStiple : softStiple, 82.5f),
                 new ("Luxembourg", softStiple, 82.4f),
-                new (
-                     "Sweden",
-                     !verticalBars
-                         ? mediumStiple
-                         : softStiple,
-                     82.4f
-                    ),
+                new ("Sweden", !verticalBars ? mediumStiple : softStiple, 82.4f),
                 new ("Iceland", softStiple, 82.3f),
-                new (
-                     "Canada",
-                     !verticalBars
-                         ? mediumStiple
-                         : softStiple,
-                     82.2f
-                    ),
+                new ("Canada", !verticalBars ? mediumStiple : softStiple, 82.2f),
                 new ("New Zealand", softStiple, 82),
-                new (
-                     "Malta",
-                     !verticalBars
-                         ? mediumStiple
-                         : softStiple,
-                     81.9f
-                    ),
+                new ("Malta", !verticalBars ? mediumStiple : softStiple, 81.9f),
                 new ("Ireland", softStiple, 81.8f)
-            }
+            ]
         };
 
         _graphView.Series.Add (barSeries);
@@ -526,50 +488,62 @@ public class GraphViewExample : Scenario
 
     private void SetupLineGraph ()
     {
+        if (_graphView is null || _about is null)
+        {
+            return;
+        }
+
         _graphView.Reset ();
 
         _graphView.Title = "Line";
 
         _about.Text = "This graph shows random points";
 
-        var black = new Attribute (_graphView.GetAttributeForRole (VisualRole.Normal).Foreground, Color.Black, _graphView.GetAttributeForRole (VisualRole.Normal).Style);
-        var cyan = new Attribute (Color.BrightCyan, Color.Black);
-        var magenta = new Attribute (Color.BrightMagenta, Color.Black);
-        var red = new Attribute (Color.BrightRed, Color.Black);
+        Attribute black = new (
+                               _graphView.GetAttributeForRole (VisualRole.Normal).Foreground,
+                               Color.Black,
+                               _graphView.GetAttributeForRole (VisualRole.Normal).Style);
+        Attribute cyan = new (Color.BrightCyan, Color.Black);
+        Attribute magenta = new (Color.BrightMagenta, Color.Black);
+        Attribute red = new (Color.BrightRed, Color.Black);
 
         _graphView.GraphColor = black;
 
-        List<PointF> randomPoints = new ();
+        List<PointF> randomPoints = [];
 
-        var r = new Random ();
+        Random r = new ();
 
         for (var i = 0; i < 10; i++)
         {
             randomPoints.Add (new (r.Next (100), r.Next (100)));
         }
 
-        var points = new ScatterSeries { Points = randomPoints };
+        ScatterSeries points = new () { Points = randomPoints };
 
-        var line = new PathAnnotation
+        PathAnnotation line = new ()
         {
-            LineColor = cyan, Points = randomPoints.OrderBy (p => p.X).ToList (), BeforeSeries = true
+            LineColor = cyan,
+            Points = randomPoints.OrderBy (p => p.X).ToList (),
+            BeforeSeries = true
         };
 
         _graphView.Series.Add (points);
         _graphView.Annotations.Add (line);
 
-        randomPoints = new ();
+        randomPoints = [];
 
         for (var i = 0; i < 10; i++)
         {
             randomPoints.Add (new (r.Next (100), r.Next (100)));
         }
 
-        var points2 = new ScatterSeries { Points = randomPoints, Fill = new ((Rune)'x', red) };
+        ScatterSeries points2 = new () { Points = randomPoints, Fill = new ((Rune)'x', red) };
 
-        var line2 = new PathAnnotation
+        PathAnnotation line2 = new ()
         {
-            LineColor = magenta, Points = randomPoints.OrderBy (p => p.X).ToList (), BeforeSeries = true
+            LineColor = magenta,
+            Points = randomPoints.OrderBy (p => p.X).ToList (),
+            BeforeSeries = true
         };
 
         _graphView.Series.Add (points2);
@@ -609,6 +583,11 @@ public class GraphViewExample : Scenario
 
     private void SetupPeriodicTableScatterPlot ()
     {
+        if (_graphView is null || _about is null)
+        {
+            return;
+        }
+
         _graphView.Reset ();
 
         _graphView.Title = "Scatter Plot";
@@ -620,8 +599,8 @@ public class GraphViewExample : Scenario
         _graphView.Series.Add (
                                new ScatterSeries
                                {
-                                   Points = new ()
-                                   {
+                                   Points =
+                                   [
                                        new (1, 1.007f),
                                        new (2, 4.002f),
                                        new (3, 6.941f),
@@ -737,7 +716,7 @@ public class GraphViewExample : Scenario
                                        new (116, 292),
                                        new (117, 295),
                                        new (118, 294)
-                                   }
+                                   ]
                                }
                               );
 
@@ -764,29 +743,10 @@ public class GraphViewExample : Scenario
 
     private void SetupPopulationPyramid ()
     {
-        /*
-        Age,M,F
-0-4,2009363,1915127
-5-9,2108550,2011016
-10-14,2022370,1933970
-15-19,1880611,1805522
-20-24,2072674,2001966
-25-29,2275138,2208929
-30-34,2361054,2345774
-35-39,2279836,2308360
-40-44,2148253,2159877
-45-49,2128343,2167778
-50-54,2281421,2353119
-55-59,2232388,2306537
-60-64,1919839,1985177
-65-69,1647391,1734370
-70-74,1624635,1763853
-75-79,1137438,1304709
-80-84,766956,969611
-85-89,438663,638892
-90-94,169952,320625
-95-99,34524,95559
-100+,3016,12818*/
+        if (_graphView is null || _about is null)
+        {
+            return;
+        }
 
         _about.Text = "This graph shows population of each age divided by gender";
 
@@ -816,16 +776,16 @@ public class GraphViewExample : Scenario
         _graphView.AxisY.ShowLabelsEvery = 0;
         _graphView.AxisY.Minimum = 0;
 
-        var stiple = new GraphCellToRender (Glyphs.Stipple);
+        GraphCellToRender stiple = new (Glyphs.Stipple);
 
         // Bars in 2 directions
 
         // Males (negative to make the bars go left)
-        var malesSeries = new BarSeries
+        BarSeries malesSeries = new ()
         {
             Orientation = Orientation.Horizontal,
-            Bars = new ()
-            {
+            Bars =
+            [
                 new ("0-4", stiple, -2009363),
                 new ("5-9", stiple, -2108550),
                 new ("10-14", stiple, -2022370),
@@ -847,16 +807,16 @@ public class GraphViewExample : Scenario
                 new ("90-94", stiple, -169952),
                 new ("95-99", stiple, -34524),
                 new ("100+", stiple, -3016)
-            }
+            ]
         };
         _graphView.Series.Add (malesSeries);
 
         // Females
-        var femalesSeries = new BarSeries
+        BarSeries femalesSeries = new ()
         {
             Orientation = Orientation.Horizontal,
-            Bars = new ()
-            {
+            Bars =
+            [
                 new ("0-4", stiple, 1915127),
                 new ("5-9", stiple, 2011016),
                 new ("10-14", stiple, 1933970),
@@ -878,11 +838,11 @@ public class GraphViewExample : Scenario
                 new ("90-94", stiple, 320625),
                 new ("95-99", stiple, 95559),
                 new ("100+", stiple, 12818)
-            }
+            ]
         };
 
-        var softStiple = new GraphCellToRender ((Rune)'\u2591');
-        var mediumStiple = new GraphCellToRender ((Rune)'\u2592');
+        GraphCellToRender softStiple = new ((Rune)'\u2591');
+        GraphCellToRender mediumStiple = new ((Rune)'\u2592');
 
         for (var i = 0; i < malesSeries.Bars.Count; i++)
         {
@@ -903,14 +863,19 @@ public class GraphViewExample : Scenario
 
     private void SetupSineWave ()
     {
+        if (_graphView is null || _about is null)
+        {
+            return;
+        }
+
         _graphView.Reset ();
 
         _graphView.Title = "Sine Wave";
 
         _about.Text = "This graph shows a sine wave";
 
-        var points = new ScatterSeries ();
-        var line = new PathAnnotation ();
+        ScatterSeries points = new ();
+        PathAnnotation line = new ();
 
         // Draw line first so it does not draw over top of points or axis labels
         line.BeforeSeries = true;
@@ -950,25 +915,33 @@ public class GraphViewExample : Scenario
 
     private void ShowBorder ()
     {
-        _miShowBorder.Checked = !_miShowBorder.Checked;
+        if (_graphView is null)
+        {
+            return;
+        }
 
-        if (_miShowBorder.Checked == true)
+        if (_showBorderCheckBox?.CheckedState == CheckState.Checked)
         {
             _graphView.BorderStyle = LineStyle.Single;
-            _graphView.Border.Thickness = _thickness;
-            _graphView.Margin.Thickness = _thickness;
-            _graphView.Padding.Thickness = _thickness;
+            _graphView.Border!.Thickness = _thickness;
+            _graphView.Margin!.Thickness = _thickness;
+            _graphView.Padding!.Thickness = _thickness;
         }
         else
         {
             _graphView.BorderStyle = LineStyle.None;
-            _graphView.Margin.Thickness = Thickness.Empty;
-            _graphView.Padding.Thickness = Thickness.Empty;
+            _graphView.Margin!.Thickness = Thickness.Empty;
+            _graphView.Padding!.Thickness = Thickness.Empty;
         }
     }
 
     private void Zoom (float factor)
     {
+        if (_graphView is null)
+        {
+            return;
+        }
+
         _graphView.CellSize = new (
                                    _graphView.CellSize.X * factor,
                                    _graphView.CellSize.Y * factor
@@ -980,7 +953,7 @@ public class GraphViewExample : Scenario
         _graphView.SetNeedsDraw ();
     }
 
-    private class DiscoBarSeries : BarSeries
+    private sealed class DiscoBarSeries : BarSeries
     {
         private readonly Attribute _brightgreen;
         private readonly Attribute _brightred;
@@ -999,35 +972,22 @@ public class GraphViewExample : Scenario
 
         protected override void DrawBarLine (GraphView graph, Point start, Point end, BarSeriesBar beingDrawn)
         {
-            IConsoleDriver driver = Application.Driver;
-
             int x = start.X;
 
             for (int y = end.Y; y <= start.Y; y++)
             {
                 float height = graph.ScreenToGraphSpace (x, y).Y;
 
-                if (height >= 85)
-                {
-                    graph.SetAttribute (_red);
-                }
-                else if (height >= 66)
-                {
-                    graph.SetAttribute (_brightred);
-                }
-                else if (height >= 45)
-                {
-                    graph.SetAttribute (_brightyellow);
-                }
-                else if (height >= 25)
-                {
-                    graph.SetAttribute (_brightgreen);
-                }
-                else
-                {
-                    graph.SetAttribute (_green);
-                }
+                Attribute attr = height switch
+                                 {
+                                     >= 85 => _red,
+                                     >= 66 => _brightred,
+                                     >= 45 => _brightyellow,
+                                     >= 25 => _brightgreen,
+                                     _ => _green
+                                 };
 
+                graph.SetAttribute (attr);
                 graph.AddRune (x, y, beingDrawn.Fill.Rune);
             }
         }

+ 9 - 9
Examples/UICatalog/Scenarios/HexEditor.cs

@@ -14,7 +14,7 @@ public class HexEditor : Scenario
 {
     private string? _fileName;
     private HexView? _hexView;
-    private MenuItemv2? _miReadOnly;
+    private MenuItem? _miReadOnly;
     private bool _saved = true;
     private Shortcut? _scAddress;
     private Shortcut? _scInfo;
@@ -49,13 +49,13 @@ public class HexEditor : Scenario
 
         app.Add (_hexView);
 
-        var menu = new MenuBarv2
+        var menu = new MenuBar
         {
             Menus =
             [
                 new (
                      "_File",
-                     new MenuItemv2 []
+                     new MenuItem []
                      {
                          new ("_New", "", New),
                          new ("_Open", "", Open),
@@ -66,7 +66,7 @@ public class HexEditor : Scenario
                     ),
                 new (
                      "_Edit",
-                     new MenuItemv2 []
+                     new MenuItem []
                      {
                          new ("_Copy", "", Copy),
                          new ("C_ut", "", Cut),
@@ -75,7 +75,7 @@ public class HexEditor : Scenario
                     ),
                 new (
                      "_Options",
-                     new MenuItemv2 []
+                     new MenuItem []
                      {
                          _miReadOnly = new (
                                               "_Read Only",
@@ -181,7 +181,7 @@ public class HexEditor : Scenario
         }
     }
 
-    private void Copy () { MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok"); }
+    private void Copy () { MessageBox.ErrorQuery (ApplicationImpl.Instance, "Not Implemented", "Functionality not yet implemented.", "Ok"); }
 
     private void CreateDemoFile (string fileName)
     {
@@ -208,7 +208,7 @@ public class HexEditor : Scenario
         ms.Close ();
     }
 
-    private void Cut () { MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "Ok"); }
+    private void Cut () { MessageBox.ErrorQuery (ApplicationImpl.Instance, "Not Implemented", "Functionality not yet implemented.", "Ok"); }
 
     private Stream LoadFile ()
     {
@@ -216,7 +216,7 @@ public class HexEditor : Scenario
 
         if (!_saved && _hexView!.Edits.Count > 0 && _hexView.Source is {})
         {
-            if (MessageBox.ErrorQuery (
+            if (MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                        "Save",
                                        "The changes were not saved. Want to open without saving?",
                                        "_Yes",
@@ -267,7 +267,7 @@ public class HexEditor : Scenario
         d.Dispose ();
     }
 
-    private void Paste () { MessageBox.ErrorQuery ("Not Implemented", "Functionality not yet implemented.", "_Ok"); }
+    private void Paste () { MessageBox.ErrorQuery (ApplicationImpl.Instance, "Not Implemented", "Functionality not yet implemented.", "_Ok"); }
     private void Quit () { Application.RequestStop (); }
 
     private void Save ()

+ 20 - 20
Examples/UICatalog/Scenarios/Images.cs

@@ -50,8 +50,8 @@ public class Images : Scenario
     private SixelToRender _fireSixel;
     private int _fireFrameCounter;
     private bool _isDisposed;
-    private RadioGroup _rgPaletteBuilder;
-    private RadioGroup _rgDistanceAlgorithm;
+    private OptionSelector _osPaletteBuilder;
+    private OptionSelector _osDistanceAlgorithm;
     private NumericUpDown _popularityThreshold;
     private SixelToRender _sixelImage;
 
@@ -151,7 +151,7 @@ public class Images : Scenario
         _win.Add (_tabView);
 
         // Start trying to detect sixel support
-        var sixelSupportDetector = new SixelSupportDetector ();
+        var sixelSupportDetector = new SixelSupportDetector (Application.Driver);
         sixelSupportDetector.Detect (UpdateSixelSupportState);
 
         Application.Run (_win);
@@ -183,7 +183,7 @@ public class Images : Scenario
 
         if (!_sixelSupportResult.SupportsTransparency)
         {
-            if (MessageBox.Query (
+            if (MessageBox.Query (ApplicationImpl.Instance,
                                   "Transparency Not Supported",
                                   "It looks like your terminal does not support transparent sixel backgrounds. Do you want to try anyway?",
                                   "Yes",
@@ -288,7 +288,7 @@ public class Images : Scenario
         }
         catch (Exception ex)
         {
-            MessageBox.ErrorQuery ("Could not open file", ex.Message, "Ok");
+            MessageBox.ErrorQuery (ApplicationImpl.Instance, "Could not open file", ex.Message, "Ok");
 
             return;
         }
@@ -408,22 +408,22 @@ public class Images : Scenario
             Y = Pos.Bottom (_pxY) + 1
         };
 
-        _rgPaletteBuilder = new ()
+        _osPaletteBuilder = new ()
         {
-            RadioLabels = new []
-            {
+            Labels =
+            [
                 "Popularity",
                 "Median Cut"
-            },
+            ],
             X = Pos.Right (_sixelView) + 2,
             Y = Pos.Bottom (l1),
-            SelectedItem = 1
+            Value = 1
         };
 
         _popularityThreshold = new ()
         {
-            X = Pos.Right (_rgPaletteBuilder) + 1,
-            Y = Pos.Top (_rgPaletteBuilder),
+            X = Pos.Right (_osPaletteBuilder) + 1,
+            Y = Pos.Top (_osPaletteBuilder),
             Value = 8
         };
 
@@ -439,12 +439,12 @@ public class Images : Scenario
             Text = "Color Distance Algorithm",
             Width = Dim.Auto (),
             X = Pos.Right (_sixelView),
-            Y = Pos.Bottom (_rgPaletteBuilder) + 1
+            Y = Pos.Bottom (_osPaletteBuilder) + 1
         };
 
-        _rgDistanceAlgorithm = new ()
+        _osDistanceAlgorithm = new ()
         {
-            RadioLabels = new []
+            Labels = new []
             {
                 "Euclidian",
                 "CIE76"
@@ -458,10 +458,10 @@ public class Images : Scenario
         _sixelSupported.Add (lblPxY);
         _sixelSupported.Add (_pxY);
         _sixelSupported.Add (l1);
-        _sixelSupported.Add (_rgPaletteBuilder);
+        _sixelSupported.Add (_osPaletteBuilder);
 
         _sixelSupported.Add (l2);
-        _sixelSupported.Add (_rgDistanceAlgorithm);
+        _sixelSupported.Add (_osDistanceAlgorithm);
         _sixelSupported.Add (_popularityThreshold);
         _sixelSupported.Add (lblPopThreshold);
 
@@ -470,7 +470,7 @@ public class Images : Scenario
 
     private IPaletteBuilder GetPaletteBuilder ()
     {
-        switch (_rgPaletteBuilder.SelectedItem)
+        switch (_osPaletteBuilder.Value)
         {
             case 0: return new PopularityPaletteWithThreshold (GetDistanceAlgorithm (), _popularityThreshold.Value);
             case 1: return new MedianCutPaletteBuilder (GetDistanceAlgorithm ());
@@ -480,7 +480,7 @@ public class Images : Scenario
 
     private IColorDistance GetDistanceAlgorithm ()
     {
-        switch (_rgDistanceAlgorithm.SelectedItem)
+        switch (_osDistanceAlgorithm.Value)
         {
             case 0: return new EuclideanColorDistance ();
             case 1: return new CIE76ColorDistance ();
@@ -492,7 +492,7 @@ public class Images : Scenario
     {
         if (_imageView.FullResImage == null)
         {
-            MessageBox.Query ("No Image Loaded", "You must first open an image.  Use the 'Open Image' button above.", "Ok");
+            MessageBox.Query (ApplicationImpl.Instance, "No Image Loaded", "You must first open an image.  Use the 'Open Image' button above.", "Ok");
 
             return;
         }

+ 71 - 43
Examples/UICatalog/Scenarios/InteractiveTree.cs

@@ -1,4 +1,4 @@
-using System.Linq;
+#nullable enable
 
 namespace UICatalog.Scenarios;
 
@@ -7,46 +7,54 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("TreeView")]
 public class InteractiveTree : Scenario
 {
-    private TreeView _treeView;
+    private TreeView? _treeView;
 
     public override void Main ()
     {
         Application.Init ();
-        var appWindow = new Toplevel ()
+
+        Window appWindow = new ()
         {
             Title = GetName (),
+            BorderStyle = LineStyle.None    
         };
 
-        var menu = new MenuBar
-        {
-            Menus =
-            [
-                new ("_File", new MenuItem [] { new ("_Quit", "", Quit) })
-            ]
-        };
-        appWindow.Add (menu);
+        // MenuBar
+        MenuBar menu = new ();
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_File",
+                                   [
+                                       new MenuItem
+                                       {
+                                           Title = "_Quit",
+                                           Action = Quit
+                                       }
+                                   ]
+                                  )
+                 );
 
         _treeView = new ()
         {
             X = 0,
-            Y = 1,
+            Y = Pos.Bottom (menu),
             Width = Dim.Fill (),
             Height = Dim.Fill (1)
         };
         _treeView.KeyDown += TreeView_KeyPress;
 
-        appWindow.Add (_treeView);
+        // StatusBar
+        StatusBar statusBar = new (
+                                   [
+                                       new (Application.QuitKey, "Quit", Quit),
+                                       new (Key.C.WithCtrl, "Add Child", AddChildNode),
+                                       new (Key.T.WithCtrl, "Add Root", AddRootNode),
+                                       new (Key.R.WithCtrl, "Rename Node", RenameNode)
+                                   ]
+                                  );
 
-        var statusBar = new StatusBar (
-                                       new Shortcut []
-                                       {
-                                           new (Application.QuitKey, "Quit", Quit),
-                                           new (Key.C.WithCtrl, "Add Child", AddChildNode),
-                                           new (Key.T.WithCtrl, "Add Root", AddRootNode),
-                                           new (Key.R.WithCtrl, "Rename Node", RenameNode)
-                                       }
-                                      );
-        appWindow.Add (statusBar);
+        appWindow.Add (menu, _treeView, statusBar);
 
         Application.Run (appWindow);
         appWindow.Dispose ();
@@ -55,9 +63,14 @@ public class InteractiveTree : Scenario
 
     private void AddChildNode ()
     {
-        ITreeNode node = _treeView.SelectedObject;
+        if (_treeView is null)
+        {
+            return;
+        }
 
-        if (node != null)
+        ITreeNode? node = _treeView.SelectedObject;
+
+        if (node is { })
         {
             if (GetText ("Text", "Enter text for node:", "", out string entered))
             {
@@ -69,6 +82,11 @@ public class InteractiveTree : Scenario
 
     private void AddRootNode ()
     {
+        if (_treeView is null)
+        {
+            return;
+        }
+
         if (GetText ("Text", "Enter text for node:", "", out string entered))
         {
             _treeView.AddObject (new TreeNode (entered));
@@ -79,20 +97,20 @@ public class InteractiveTree : Scenario
     {
         var okPressed = false;
 
-        var ok = new Button { Text = "Ok", IsDefault = true };
+        Button ok = new () { Text = "Ok", IsDefault = true };
 
         ok.Accepting += (s, e) =>
-                     {
-                         okPressed = true;
-                         Application.RequestStop ();
-                     };
-        var cancel = new Button { Text = "Cancel" };
+                        {
+                            okPressed = true;
+                            Application.RequestStop ();
+                        };
+        Button cancel = new () { Text = "Cancel" };
         cancel.Accepting += (s, e) => Application.RequestStop ();
-        var d = new Dialog { Title = title, Buttons = [ok, cancel] };
+        Dialog d = new () { Title = title, Buttons = [ok, cancel] };
 
-        var lbl = new Label { X = 0, Y = 1, Text = label };
+        Label lbl = new () { X = 0, Y = 1, Text = label };
 
-        var tf = new TextField { Text = initialText, X = 0, Y = 2, Width = Dim.Fill () };
+        TextField tf = new () { Text = initialText, X = 0, Y = 2, Width = Dim.Fill () };
 
         d.Add (lbl, tf);
         tf.SetFocus ();
@@ -100,7 +118,7 @@ public class InteractiveTree : Scenario
         Application.Run (d);
         d.Dispose ();
 
-        enteredText = okPressed ? tf.Text : null;
+        enteredText = okPressed ? tf.Text : string.Empty;
 
         return okPressed;
     }
@@ -109,9 +127,14 @@ public class InteractiveTree : Scenario
 
     private void RenameNode ()
     {
-        ITreeNode node = _treeView.SelectedObject;
+        if (_treeView is null)
+        {
+            return;
+        }
+
+        ITreeNode? node = _treeView.SelectedObject;
 
-        if (node != null)
+        if (node is { })
         {
             if (GetText ("Text", "Enter text for node:", node.Text, out string entered))
             {
@@ -121,13 +144,18 @@ public class InteractiveTree : Scenario
         }
     }
 
-    private void TreeView_KeyPress (object sender, Key obj)
+    private void TreeView_KeyPress (object? sender, Key obj)
     {
+        if (_treeView is null)
+        {
+            return;
+        }
+
         if (obj.KeyCode == Key.Delete)
         {
-            ITreeNode toDelete = _treeView.SelectedObject;
+            ITreeNode? toDelete = _treeView.SelectedObject;
 
-            if (toDelete == null)
+            if (toDelete is null)
             {
                 return;
             }
@@ -141,11 +169,11 @@ public class InteractiveTree : Scenario
             }
             else
             {
-                ITreeNode parent = _treeView.GetParent (toDelete);
+                ITreeNode? parent = _treeView.GetParent (toDelete);
 
-                if (parent == null)
+                if (parent is null)
                 {
-                    MessageBox.ErrorQuery (
+                    MessageBox.ErrorQuery (ApplicationImpl.Instance,
                                            "Could not delete",
                                            $"Parent of '{toDelete}' was unexpectedly null",
                                            "Ok"

+ 4 - 4
Examples/UICatalog/Scenarios/KeyBindings.cs

@@ -164,17 +164,17 @@ public class KeyBindingsDemo : View
 
         AddCommand (Command.Save, ctx =>
                                  {
-                                     MessageBox.Query ($"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
+                                     MessageBox.Query (ApplicationImpl.Instance, $"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
                                      return true;
                                  });
         AddCommand (Command.New, ctx =>
                                 {
-                                    MessageBox.Query ($"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
+                                    MessageBox.Query (ApplicationImpl.Instance, $"{ctx.Command}", $"Ctx: {ctx}", buttons: "Ok");
                                     return true;
                                 });
         AddCommand (Command.HotKey, ctx =>
         {
-            MessageBox.Query ($"{ctx.Command}", $"Ctx: {ctx}\nCommand: {ctx.Command}", buttons: "Ok");
+            MessageBox.Query (ApplicationImpl.Instance, $"{ctx.Command}", $"Ctx: {ctx}\nCommand: {ctx.Command}", buttons: "Ok");
             SetFocus ();
             return true;
         });
@@ -189,7 +189,7 @@ public class KeyBindingsDemo : View
                                              {
                                                  return false;
                                              }
-                                             MessageBox.Query ($"{keyCommandContext.Binding}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
+                                             MessageBox.Query (ApplicationImpl.Instance, $"{keyCommandContext.Binding}", $"Key: {keyCommandContext.Binding.Key}\nCommand: {ctx.Command}", buttons: "Ok");
                                              Application.RequestStop ();
                                              return true;
                                          });

+ 5 - 8
Examples/UICatalog/Scenarios/Keys.cs

@@ -86,7 +86,7 @@ public class Keys : Scenario
             Height = Dim.Fill (),
             Source = new ListWrapper<string> (keyList)
         };
-        appKeyListView.SchemeName = "TopLevel";
+        appKeyListView.SchemeName = "Runnable";
         win.Add (appKeyListView);
 
         // View key events...
@@ -114,7 +114,7 @@ public class Keys : Scenario
             Height = Dim.Fill (),
             Source = new ListWrapper<string> (keyDownList)
         };
-        appKeyListView.SchemeName = "TopLevel";
+        appKeyListView.SchemeName = "Runnable";
         win.Add (onKeyDownListView);
 
         // KeyDownNotHandled
@@ -134,7 +134,7 @@ public class Keys : Scenario
             Height = Dim.Fill (),
             Source = new ListWrapper<string> (keyDownNotHandledList)
         };
-        appKeyListView.SchemeName = "TopLevel";
+        appKeyListView.SchemeName = "Runnable";
         win.Add (onKeyDownNotHandledListView);
 
 
@@ -155,13 +155,10 @@ public class Keys : Scenario
             Height = Dim.Fill (),
             Source = new ListWrapper<string> (swallowedList)
         };
-        appKeyListView.SchemeName = "TopLevel";
+        appKeyListView.SchemeName = "Runnable";
         win.Add (onSwallowedListView);
 
-        if (Application.Driver is IConsoleDriverFacade fac)
-        {
-            fac.InputProcessor.AnsiSequenceSwallowed += (s, e) => { swallowedList.Add (e.Replace ("\x1b","Esc")); };
-        }
+        Application.Driver!.InputProcessor.AnsiSequenceSwallowed += (s, e) => { swallowedList.Add (e.Replace ("\x1b", "Esc")); };
 
         Application.KeyDown += (s, a) => KeyDownPressUp (a, "Down");
         Application.KeyUp += (s, a) => KeyDownPressUp (a, "Up");

+ 4 - 4
Examples/UICatalog/Scenarios/LineCanvasExperiment.cs

@@ -101,7 +101,7 @@ public class LineCanvasExperiment : Scenario
         //    Width = view4.Width,
         //    Height = 5,
 
-        //    //Scheme = Colors.Schemes ["TopLevel"],
+        //    //Scheme = Colors.Schemes ["Runnable"],
         //    SuperViewRendersLineCanvas = true,
         //    BorderStyle = LineStyle.Double
         //};
@@ -130,9 +130,9 @@ public class LineCanvasExperiment : Scenario
         //    //Scheme = Colors.Schemes ["Error"],
         //    SuperViewRendersLineCanvas = true
         //};
-        //marginWindow.Margin.Scheme = Colors.Schemes ["Error"];
-        //marginWindow.Margin.Thickness = new (1);
-        //marginWindow.Border.Thickness = new (1, 2, 1, 1);
+        //marginWindow.Margin!.Scheme = Colors.Schemes ["Error"];
+        //marginWindow.Margin!.Thickness = new (1);
+        //marginWindow.Border!.Thickness = new (1, 2, 1, 1);
 
         //frame1.Add (marginWindow);
 

+ 11 - 5
Examples/UICatalog/Scenarios/LineDrawing.cs

@@ -210,7 +210,7 @@ public class ToolsView : Window
 {
     private Button _addLayerBtn;
     private readonly AttributeView _colors;
-    private RadioGroup _stylePicker;
+    private OptionSelector<LineStyle> _stylePicker;
 
     public Attribute CurrentColor
     {
@@ -236,10 +236,16 @@ public class ToolsView : Window
 
         _stylePicker = new ()
         {
-            X = 0, Y = Pos.Bottom (_colors), RadioLabels = Enum.GetNames (typeof (LineStyle)).ToArray ()
+            X = 0, Y = Pos.Bottom (_colors), AssignHotKeys = true
         };
-        _stylePicker.SelectedItemChanged += (s, a) => { SetStyle?.Invoke ((LineStyle)a.SelectedItem); };
-        _stylePicker.SelectedItem = 1;
+        _stylePicker.ValueChanged += (s, a) =>
+                                     {
+                                         if (a.Value is { })
+                                         {
+                                             SetStyle?.Invoke ((LineStyle)a.Value);
+                                         }
+                                     };
+        _stylePicker.Value = LineStyle.Single;
 
         _addLayerBtn = new () { Text = "New Layer", X = Pos.Center (), Y = Pos.Bottom (_stylePicker) };
 
@@ -278,7 +284,7 @@ public class DrawingArea : View
                     SetCurrentAttribute (c.Value.Value.Attribute ?? GetAttributeForRole (VisualRole.Normal));
 
                     // TODO: #2616 - Support combining sequences that don't normalize
-                    AddRune (c.Key.X, c.Key.Y, c.Value.Value.Rune);
+                    AddStr (c.Key.X, c.Key.Y, c.Value.Value.Grapheme);
                 }
             }
         }

+ 309 - 268
Examples/UICatalog/Scenarios/ListColumns.cs

@@ -1,6 +1,6 @@
-using System;
+#nullable enable
+
 using System.Collections;
-using System.Collections.Generic;
 using System.Data;
 
 namespace UICatalog.Scenarios;
@@ -13,19 +13,19 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Scrolling")]
 public class ListColumns : Scenario
 {
-    private Scheme _alternatingScheme;
-    private DataTable _currentTable;
-    private TableView _listColView;
-    private MenuItem _miAlternatingColors;
-    private MenuItem _miAlwaysUseNormalColorForVerticalCellLines;
-    private MenuItem _miBottomline;
-    private MenuItem _miCellLines;
-    private MenuItem _miCursor;
-    private MenuItem _miExpandLastColumn;
-    private MenuItem _miOrientVertical;
-    private MenuItem _miScrollParallel;
-    private MenuItem _miSmoothScrolling;
-    private MenuItem _miTopline;
+    private Scheme? _alternatingScheme;
+    private DataTable? _currentTable;
+    private TableView? _listColView;
+    private CheckBox? _alternatingColorsCheckBox;
+    private CheckBox? _alwaysUseNormalColorForVerticalCellLinesCheckBox;
+    private CheckBox? _bottomlineCheckBox;
+    private CheckBox? _cellLinesCheckBox;
+    private CheckBox? _cursorCheckBox;
+    private CheckBox? _expandLastColumnCheckBox;
+    private CheckBox? _orientVerticalCheckBox;
+    private CheckBox? _scrollParallelCheckBox;
+    private CheckBox? _smoothScrollingCheckBox;
+    private CheckBox? _toplineCheckBox;
 
     /// <summary>
     ///     Builds a simple list in which values are the index.  This helps testing that scrolling etc is working
@@ -35,7 +35,7 @@ public class ListColumns : Scenario
     /// <returns></returns>
     public static IList BuildSimpleList (int items)
     {
-        List<object> list = new ();
+        List<object> list = [];
 
         for (var i = 0; i < items; i++)
         {
@@ -47,20 +47,22 @@ public class ListColumns : Scenario
 
     public override void Main ()
     {
-        // Init
         Application.Init ();
 
-        // Setup - Create a top-level application window and configure it.
-        Toplevel top = new ();
         Window appWindow = new ()
         {
-            Title = GetQuitKeyAndName ()
+            Title = GetQuitKeyAndName (),
+            BorderStyle = LineStyle.None
         };
 
+        // MenuBar
+        MenuBar menuBar = new ();
+
         _listColView = new ()
         {
+            Y = Pos.Bottom(menuBar),
             Width = Dim.Fill (),
-            Height = Dim.Fill (),
+            Height = Dim.Fill (1),
             Style = new ()
             {
                 ShowHeaders = false,
@@ -70,178 +72,43 @@ public class ListColumns : Scenario
                 ExpandLastColumn = false
             }
         };
-        var listColStyle = new ListColumnStyle ();
-
-        var menu = new MenuBar
-        {
-            Menus =
-            [
-                new (
-                     "_File",
-                     new MenuItem []
-                     {
-                         new (
-                              "Open_BigListExample",
-                              "",
-                              () => OpenSimpleList (true)
-                             ),
-                         new (
-                              "Open_SmListExample",
-                              "",
-                              () => OpenSimpleList (false)
-                             ),
-                         new (
-                              "_CloseExample",
-                              "",
-                              () => CloseExample ()
-                             ),
-                         new ("_Quit", "", () => Quit ())
-                     }
-                    ),
-                new (
-                     "_View",
-                     new []
-                     {
-                         _miTopline =
-                             new ("_TopLine", "", () => ToggleTopline ())
-                             {
-                                 Checked = _listColView.Style
-                                                       .ShowHorizontalHeaderOverline,
-                                 CheckType = MenuItemCheckStyle.Checked
-                             },
-                         _miBottomline = new (
-                                              "_BottomLine",
-                                              "",
-                                              () => ToggleBottomline ()
-                                             )
-                         {
-                             Checked = _listColView.Style
-                                                   .ShowHorizontalBottomline,
-                             CheckType = MenuItemCheckStyle.Checked
-                         },
-                         _miCellLines = new (
-                                             "_CellLines",
-                                             "",
-                                             () => ToggleCellLines ()
-                                            )
-                         {
-                             Checked = _listColView.Style
-                                                   .ShowVerticalCellLines,
-                             CheckType = MenuItemCheckStyle.Checked
-                         },
-                         _miExpandLastColumn = new (
-                                                    "_ExpandLastColumn",
-                                                    "",
-                                                    () => ToggleExpandLastColumn ()
-                                                   )
-                         {
-                             Checked = _listColView.Style.ExpandLastColumn,
-                             CheckType = MenuItemCheckStyle.Checked
-                         },
-                         _miAlwaysUseNormalColorForVerticalCellLines =
-                             new (
-                                  "_AlwaysUseNormalColorForVerticalCellLines",
-                                  "",
-                                  () =>
-                                      ToggleAlwaysUseNormalColorForVerticalCellLines ()
-                                 )
-                             {
-                                 Checked = _listColView.Style
-                                                       .AlwaysUseNormalColorForVerticalCellLines,
-                                 CheckType = MenuItemCheckStyle.Checked
-                             },
-                         _miSmoothScrolling = new (
-                                                   "_SmoothHorizontalScrolling",
-                                                   "",
-                                                   () => ToggleSmoothScrolling ()
-                                                  )
-                         {
-                             Checked = _listColView.Style
-                                                   .SmoothHorizontalScrolling,
-                             CheckType = MenuItemCheckStyle.Checked
-                         },
-                         _miAlternatingColors = new (
-                                                     "Alternating Colors",
-                                                     "",
-                                                     () => ToggleAlternatingColors ()
-                                                    ) { CheckType = MenuItemCheckStyle.Checked },
-                         _miCursor = new (
-                                          "Invert Selected Cell First Character",
-                                          "",
-                                          () =>
-                                              ToggleInvertSelectedCellFirstCharacter ()
-                                         )
-                         {
-                             Checked = _listColView.Style
-                                                   .InvertSelectedCellFirstCharacter,
-                             CheckType = MenuItemCheckStyle.Checked
-                         }
-                     }
-                    ),
-                new (
-                     "_List",
-                     new []
-                     {
-                         //new MenuItem ("_Hide Headers", "", HideHeaders),
-                         _miOrientVertical = new (
-                                                  "_OrientVertical",
-                                                  "",
-                                                  () => ToggleVerticalOrientation ()
-                                                 )
-                         {
-                             Checked = listColStyle.Orientation
-                                       == Orientation.Vertical,
-                             CheckType = MenuItemCheckStyle.Checked
-                         },
-                         _miScrollParallel = new (
-                                                  "_ScrollParallel",
-                                                  "",
-                                                  () => ToggleScrollParallel ()
-                                                 )
-                         {
-                             Checked = listColStyle.ScrollParallel,
-                             CheckType = MenuItemCheckStyle.Checked
-                         },
-                         new ("Set _Max Cell Width", "", SetListMaxWidth),
-                         new ("Set Mi_n Cell Width", "", SetListMinWidth)
-                     }
-                    )
-            ]
-        };
+        ListColumnStyle listColStyle = new ();
 
-        var statusBar = new StatusBar (
-                                       new Shortcut []
-                                       {
-                                           new (Key.F2, "OpenBigListEx", () => OpenSimpleList (true)),
-                                           new (Key.F3, "CloseExample", CloseExample),
-                                           new (Key.F4, "OpenSmListEx", () => OpenSimpleList (false)),
-                                           new (Application.QuitKey, "Quit", Quit)
-                                       }
-                                      );
-        appWindow.Add (_listColView);
 
-        var selectedCellLabel = new Label
+        // Status Bar
+        StatusBar statusBar = new (
+                                   [
+                                       new (Key.F2, "OpenBigListEx", () => OpenSimpleList (true)),
+                                       new (Key.F3, "CloseExample", CloseExample),
+                                       new (Key.F4, "OpenSmListEx", () => OpenSimpleList (false)),
+                                       new (Application.QuitKey, "Quit", Quit)
+                                   ]
+                                  );
+
+        // Selected cell label
+        Label selectedCellLabel = new ()
         {
             X = 0,
             Y = Pos.Bottom (_listColView),
             Text = "0,0",
-
             Width = Dim.Fill (),
             TextAlignment = Alignment.End
         };
 
-        appWindow.Add (selectedCellLabel);
-
-        _listColView.SelectedCellChanged += (s, e) => { selectedCellLabel.Text = $"{_listColView.SelectedRow},{_listColView.SelectedColumn}"; };
+        _listColView.SelectedCellChanged += (s, e) =>
+                                            {
+                                                if (_listColView is { })
+                                                {
+                                                    selectedCellLabel.Text = $"{_listColView.SelectedRow},{_listColView.SelectedColumn}";
+                                                }
+                                            };
         _listColView.KeyDown += TableViewKeyPress;
 
-        //SetupScrollBar ();
-
         _alternatingScheme = new ()
         {
-            Disabled = appWindow.GetAttributeForRole(VisualRole.Disabled),
+            Disabled = appWindow.GetAttributeForRole (VisualRole.Disabled),
             HotFocus = appWindow.GetAttributeForRole (VisualRole.HotFocus),
-            Focus = appWindow.GetAttributeForRole(VisualRole.Focus),
+            Focus = appWindow.GetAttributeForRole (VisualRole.Focus),
             Normal = new (Color.White, Color.BrightBlue)
         };
 
@@ -250,37 +117,210 @@ public class ListColumns : Scenario
 
         _listColView.KeyBindings.ReplaceCommands (Key.Space, Command.Accept);
 
-        top.Add (menu, appWindow, statusBar);
-        appWindow.Y = 1;
-        appWindow.Height = Dim.Fill(Dim.Func (_ => statusBar.Frame.Height));
+        // Setup menu checkboxes
+        _toplineCheckBox = new ()
+        {
+            Title = "_TopLine",
+            CheckedState = _listColView.Style.ShowHorizontalHeaderOverline ? CheckState.Checked : CheckState.UnChecked
+        };
+        _toplineCheckBox.CheckedStateChanged += (s, e) => ToggleTopline ();
+
+        _bottomlineCheckBox = new ()
+        {
+            Title = "_BottomLine",
+            CheckedState = _listColView.Style.ShowHorizontalBottomline ? CheckState.Checked : CheckState.UnChecked
+        };
+        _bottomlineCheckBox.CheckedStateChanged += (s, e) => ToggleBottomline ();
+
+        _cellLinesCheckBox = new ()
+        {
+            Title = "_CellLines",
+            CheckedState = _listColView.Style.ShowVerticalCellLines ? CheckState.Checked : CheckState.UnChecked
+        };
+        _cellLinesCheckBox.CheckedStateChanged += (s, e) => ToggleCellLines ();
+
+        _expandLastColumnCheckBox = new ()
+        {
+            Title = "_ExpandLastColumn",
+            CheckedState = _listColView.Style.ExpandLastColumn ? CheckState.Checked : CheckState.UnChecked
+        };
+        _expandLastColumnCheckBox.CheckedStateChanged += (s, e) => ToggleExpandLastColumn ();
+
+        _alwaysUseNormalColorForVerticalCellLinesCheckBox = new ()
+        {
+            Title = "_AlwaysUseNormalColorForVerticalCellLines",
+            CheckedState = _listColView.Style.AlwaysUseNormalColorForVerticalCellLines ? CheckState.Checked : CheckState.UnChecked
+        };
+        _alwaysUseNormalColorForVerticalCellLinesCheckBox.CheckedStateChanged += (s, e) => ToggleAlwaysUseNormalColorForVerticalCellLines ();
+
+        _smoothScrollingCheckBox = new ()
+        {
+            Title = "_SmoothHorizontalScrolling",
+            CheckedState = _listColView.Style.SmoothHorizontalScrolling ? CheckState.Checked : CheckState.UnChecked
+        };
+        _smoothScrollingCheckBox.CheckedStateChanged += (s, e) => ToggleSmoothScrolling ();
+
+        _alternatingColorsCheckBox = new ()
+        {
+            Title = "Alternating Colors"
+        };
+        _alternatingColorsCheckBox.CheckedStateChanged += (s, e) => ToggleAlternatingColors ();
 
-        // Run - Start the application.
-        Application.Run (top);
-        top.Dispose ();
+        _cursorCheckBox = new ()
+        {
+            Title = "Invert Selected Cell First Character",
+            CheckedState = _listColView.Style.InvertSelectedCellFirstCharacter ? CheckState.Checked : CheckState.UnChecked
+        };
+        _cursorCheckBox.CheckedStateChanged += (s, e) => ToggleInvertSelectedCellFirstCharacter ();
 
-        // Shutdown - Calling Application.Shutdown is required.
+        _orientVerticalCheckBox = new ()
+        {
+            Title = "_OrientVertical",
+            CheckedState = listColStyle.Orientation == Orientation.Vertical ? CheckState.Checked : CheckState.UnChecked
+        };
+        _orientVerticalCheckBox.CheckedStateChanged += (s, e) => ToggleVerticalOrientation ();
+
+        _scrollParallelCheckBox = new ()
+        {
+            Title = "_ScrollParallel",
+            CheckedState = listColStyle.ScrollParallel ? CheckState.Checked : CheckState.UnChecked
+        };
+        _scrollParallelCheckBox.CheckedStateChanged += (s, e) => ToggleScrollParallel ();
+
+        menuBar.Add (
+                  new MenuBarItem (
+                                   "_File",
+                                   [
+                                       new MenuItem
+                                       {
+                                           Title = "Open_BigListExample",
+                                           Action = () => OpenSimpleList (true)
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "Open_SmListExample",
+                                           Action = () => OpenSimpleList (false)
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_CloseExample",
+                                           Action = CloseExample
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Quit",
+                                           Action = Quit
+                                       }
+                                   ]
+                                  )
+                 );
+
+        menuBar.Add (
+                  new MenuBarItem (
+                                   "_View",
+                                   [
+                                       new MenuItem
+                                       {
+                                           CommandView = _toplineCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _bottomlineCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _cellLinesCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _expandLastColumnCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _alwaysUseNormalColorForVerticalCellLinesCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _smoothScrollingCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _alternatingColorsCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _cursorCheckBox
+                                       }
+                                   ]
+                                  )
+                 );
+
+        menuBar.Add (
+                  new MenuBarItem (
+                                   "_List",
+                                   [
+                                       new MenuItem
+                                       {
+                                           CommandView = _orientVerticalCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           CommandView = _scrollParallelCheckBox
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "Set _Max Cell Width",
+                                           Action = SetListMaxWidth
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "Set Mi_n Cell Width",
+                                           Action = SetListMinWidth
+                                       }
+                                   ]
+                                  )
+                 );
+
+        // Add views in order of visual appearance
+        appWindow.Add (menuBar, _listColView, selectedCellLabel, statusBar);
+
+        Application.Run (appWindow);
+        appWindow.Dispose ();
         Application.Shutdown ();
     }
 
-    private void CloseExample () { _listColView.Table = null; }
+    private void CloseExample ()
+    {
+        if (_listColView is { })
+        {
+            _listColView.Table = null;
+        }
+    }
+
     private void OpenSimpleList (bool big) { SetTable (BuildSimpleList (big ? 1023 : 31)); }
+
     private void Quit () { Application.RequestStop (); }
 
     private void RunListWidthDialog (string prompt, Action<TableView, int> setter, Func<TableView, int> getter)
     {
+        if (_listColView is null)
+        {
+            return;
+        }
+
         var accepted = false;
-        var ok = new Button { Text = "Ok", IsDefault = true };
+        Button ok = new () { Text = "Ok", IsDefault = true };
 
         ok.Accepting += (s, e) =>
-                     {
-                         accepted = true;
-                         Application.RequestStop ();
-                     };
-        var cancel = new Button { Text = "Cancel" };
+                        {
+                            accepted = true;
+                            Application.RequestStop ();
+                        };
+        Button cancel = new () { Text = "Cancel" };
         cancel.Accepting += (s, e) => { Application.RequestStop (); };
-        var d = new Dialog { Title = prompt, Buttons = [ok, cancel] };
+        Dialog d = new () { Title = prompt, Buttons = [ok, cancel] };
 
-        var tf = new TextField { Text = getter (_listColView).ToString (), X = 0, Y = 0, Width = Dim.Fill () };
+        TextField tf = new () { Text = getter (_listColView).ToString (), X = 0, Y = 0, Width = Dim.Fill () };
 
         d.Add (tf);
         tf.SetFocus ();
@@ -296,7 +336,7 @@ public class ListColumns : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (60, 20, "Failed to set", ex.Message, "Ok");
+                MessageBox.ErrorQuery (ApplicationImpl.Instance, 60, 20, "Failed to set", ex.Message, "Ok");
             }
         }
     }
@@ -304,63 +344,37 @@ public class ListColumns : Scenario
     private void SetListMaxWidth ()
     {
         RunListWidthDialog ("MaxCellWidth", (s, v) => s.MaxCellWidth = v, s => s.MaxCellWidth);
-        _listColView.SetNeedsDraw ();
+        _listColView?.SetNeedsDraw ();
     }
 
     private void SetListMinWidth ()
     {
         RunListWidthDialog ("MinCellWidth", (s, v) => s.MinCellWidth = v, s => s.MinCellWidth);
-        _listColView.SetNeedsDraw ();
+        _listColView?.SetNeedsDraw ();
     }
 
     private void SetTable (IList list)
     {
+        if (_listColView is null)
+        {
+            return;
+        }
+
         _listColView.Table = new ListTableSource (list, _listColView);
 
-        if ((ListTableSource)_listColView.Table != null)
+        if (_listColView.Table is ListTableSource listTableSource)
         {
-            _currentTable = ((ListTableSource)_listColView.Table).DataTable;
+            _currentTable = listTableSource.DataTable;
         }
     }
 
-    //private void SetupScrollBar ()
-    //{
-    //    var scrollBar = new ScrollBarView (_listColView, true); // (listColView, true, true);
-
-    //    scrollBar.ChangedPosition += (s, e) =>
-    //                                 {
-    //                                     _listColView.RowOffset = scrollBar.Position;
-
-    //                                     if (_listColView.RowOffset != scrollBar.Position)
-    //                                     {
-    //                                         scrollBar.Position = _listColView.RowOffset;
-    //                                     }
-
-    //                                     _listColView.SetNeedsDraw ();
-    //                                 };
-    //    /*
-    //    scrollBar.OtherScrollBarView.ChangedPosition += (s,e) => {
-    //        listColView.ColumnOffset = scrollBar.OtherScrollBarView.Position;
-    //        if (listColView.ColumnOffset != scrollBar.OtherScrollBarView.Position) {
-    //            scrollBar.OtherScrollBarView.Position = listColView.ColumnOffset;
-    //        }
-    //        listColView.SetNeedsDraw ();
-    //    };
-    //    */
-
-    //    _listColView.DrawingContent += (s, e) =>
-    //                                {
-    //                                    scrollBar.Size = _listColView.Table?.Rows ?? 0;
-    //                                    scrollBar.Position = _listColView.RowOffset;
-
-    //                                    //scrollBar.OtherScrollBarView.Size = listColView.Table?.Columns - 1 ?? 0;
-    //                                    //scrollBar.OtherScrollBarView.Position = listColView.ColumnOffset;
-    //                                    scrollBar.Refresh ();
-    //                                };
-    //}
-
-    private void TableViewKeyPress (object sender, Key e)
+    private void TableViewKeyPress (object? sender, Key e)
     {
+        if (_currentTable is null || _listColView is null)
+        {
+            return;
+        }
+
         if (e.KeyCode == Key.Delete)
         {
             // set all selected cells to null
@@ -376,12 +390,14 @@ public class ListColumns : Scenario
 
     private void ToggleAlternatingColors ()
     {
-        //toggle menu item
-        _miAlternatingColors.Checked = !_miAlternatingColors.Checked;
+        if (_listColView is null || _alternatingColorsCheckBox is null)
+        {
+            return;
+        }
 
-        if (_miAlternatingColors.Checked == true)
+        if (_alternatingColorsCheckBox.CheckedState == CheckState.Checked)
         {
-            _listColView.Style.RowColorGetter = a => { return a.RowIndex % 2 == 0 ? _alternatingScheme : null; };
+            _listColView.Style.RowColorGetter = a => a.RowIndex % 2 == 0 ? _alternatingScheme : null;
         }
         else
         {
@@ -393,81 +409,106 @@ public class ListColumns : Scenario
 
     private void ToggleAlwaysUseNormalColorForVerticalCellLines ()
     {
-        _miAlwaysUseNormalColorForVerticalCellLines.Checked =
-            !_miAlwaysUseNormalColorForVerticalCellLines.Checked;
+        if (_listColView is null || _alwaysUseNormalColorForVerticalCellLinesCheckBox is null)
+        {
+            return;
+        }
 
         _listColView.Style.AlwaysUseNormalColorForVerticalCellLines =
-            (bool)_miAlwaysUseNormalColorForVerticalCellLines.Checked;
+            _alwaysUseNormalColorForVerticalCellLinesCheckBox.CheckedState == CheckState.Checked;
 
         _listColView.Update ();
     }
 
     private void ToggleBottomline ()
     {
-        _miBottomline.Checked = !_miBottomline.Checked;
-        _listColView.Style.ShowHorizontalBottomline = (bool)_miBottomline.Checked;
+        if (_listColView is null || _bottomlineCheckBox is null)
+        {
+            return;
+        }
+
+        _listColView.Style.ShowHorizontalBottomline = _bottomlineCheckBox.CheckedState == CheckState.Checked;
         _listColView.Update ();
     }
 
     private void ToggleCellLines ()
     {
-        _miCellLines.Checked = !_miCellLines.Checked;
-        _listColView.Style.ShowVerticalCellLines = (bool)_miCellLines.Checked;
+        if (_listColView is null || _cellLinesCheckBox is null)
+        {
+            return;
+        }
+
+        _listColView.Style.ShowVerticalCellLines = _cellLinesCheckBox.CheckedState == CheckState.Checked;
         _listColView.Update ();
     }
 
     private void ToggleExpandLastColumn ()
     {
-        _miExpandLastColumn.Checked = !_miExpandLastColumn.Checked;
-        _listColView.Style.ExpandLastColumn = (bool)_miExpandLastColumn.Checked;
+        if (_listColView is null || _expandLastColumnCheckBox is null)
+        {
+            return;
+        }
+
+        _listColView.Style.ExpandLastColumn = _expandLastColumnCheckBox.CheckedState == CheckState.Checked;
 
         _listColView.Update ();
     }
 
     private void ToggleInvertSelectedCellFirstCharacter ()
     {
-        //toggle menu item
-        _miCursor.Checked = !_miCursor.Checked;
-        _listColView.Style.InvertSelectedCellFirstCharacter = (bool)_miCursor.Checked;
+        if (_listColView is null || _cursorCheckBox is null)
+        {
+            return;
+        }
+
+        _listColView.Style.InvertSelectedCellFirstCharacter = _cursorCheckBox.CheckedState == CheckState.Checked;
         _listColView.SetNeedsDraw ();
     }
 
     private void ToggleScrollParallel ()
     {
-        _miScrollParallel.Checked = !_miScrollParallel.Checked;
-
-        if ((ListTableSource)_listColView.Table != null)
+        if (_listColView?.Table is not ListTableSource listTableSource || _scrollParallelCheckBox is null)
         {
-            ((ListTableSource)_listColView.Table).Style.ScrollParallel = (bool)_miScrollParallel.Checked;
-            _listColView.SetNeedsDraw ();
+            return;
         }
+
+        listTableSource.Style.ScrollParallel = _scrollParallelCheckBox.CheckedState == CheckState.Checked;
+        _listColView.SetNeedsDraw ();
     }
 
     private void ToggleSmoothScrolling ()
     {
-        _miSmoothScrolling.Checked = !_miSmoothScrolling.Checked;
-        _listColView.Style.SmoothHorizontalScrolling = (bool)_miSmoothScrolling.Checked;
+        if (_listColView is null || _smoothScrollingCheckBox is null)
+        {
+            return;
+        }
+
+        _listColView.Style.SmoothHorizontalScrolling = _smoothScrollingCheckBox.CheckedState == CheckState.Checked;
 
         _listColView.Update ();
     }
 
     private void ToggleTopline ()
     {
-        _miTopline.Checked = !_miTopline.Checked;
-        _listColView.Style.ShowHorizontalHeaderOverline = (bool)_miTopline.Checked;
+        if (_listColView is null || _toplineCheckBox is null)
+        {
+            return;
+        }
+
+        _listColView.Style.ShowHorizontalHeaderOverline = _toplineCheckBox.CheckedState == CheckState.Checked;
         _listColView.Update ();
     }
 
     private void ToggleVerticalOrientation ()
     {
-        _miOrientVertical.Checked = !_miOrientVertical.Checked;
-
-        if ((ListTableSource)_listColView.Table != null)
+        if (_listColView?.Table is not ListTableSource listTableSource || _orientVerticalCheckBox is null)
         {
-            ((ListTableSource)_listColView.Table).Style.Orientation = (bool)_miOrientVertical.Checked
-                                                                          ? Orientation.Vertical
-                                                                          : Orientation.Horizontal;
-            _listColView.SetNeedsDraw ();
+            return;
         }
+
+        listTableSource.Style.Orientation = _orientVerticalCheckBox.CheckedState == CheckState.Checked
+                                                ? Orientation.Vertical
+                                                : Orientation.Horizontal;
+        _listColView.SetNeedsDraw ();
     }
 }

+ 5 - 5
Examples/UICatalog/Scenarios/ListViewWithSelection.cs

@@ -98,7 +98,7 @@ public class ListViewWithSelection : Scenario
             Height = Dim.Fill (),
             Source = new ListWrapper<string> (_eventList)
         };
-        _eventListView.SchemeName = "TopLevel";
+        _eventListView.SchemeName = "Runnable";
         _appWindow.Add (_eventListView);
 
         _listView.SelectedItemChanged += (s, a) => LogEvent (s as View, a, "SelectedItemChanged");
@@ -237,7 +237,7 @@ public class ListViewWithSelection : Scenario
             int col,
             int line,
             int width,
-            int start = 0
+            int viewportX = 0
         )
         {
             container.Move (col, line);
@@ -247,7 +247,7 @@ public class ListViewWithSelection : Scenario
                                       string.Format ("{{0,{0}}}", -_nameColumnWidth),
                                       Scenarios [item].GetName ()
                                      );
-            RenderUstr (container, $"{s} ({Scenarios [item].GetDescription ()})", col, line, width, start);
+            RenderUstr (container, $"{s} ({Scenarios [item].GetDescription ()})", col, line, width, viewportX);
         }
 
         public void SetMark (int item, bool value)
@@ -288,10 +288,10 @@ public class ListViewWithSelection : Scenario
         }
 
         // A slightly adapted method from: https://github.com/gui-cs/Terminal.Gui/blob/fc1faba7452ccbdf49028ac49f0c9f0f42bbae91/Terminal.Gui/Views/ListView.cs#L433-L461
-        private void RenderUstr (View view, string ustr, int col, int line, int width, int start = 0)
+        private void RenderUstr (View view, string ustr, int col, int line, int width, int viewportX = 0)
         {
             var used = 0;
-            int index = start;
+            int index = viewportX;
 
             while (index < ustr.Length)
             {

+ 3 - 3
Examples/UICatalog/Scenarios/ListsAndCombos.cs

@@ -35,7 +35,7 @@ public class ListsAndCombos : Scenario
         // ListView
         var lbListView = new Label
         {
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             X = 0,
 
             Width = Dim.Percent (40),
@@ -50,7 +50,7 @@ public class ListsAndCombos : Scenario
             Width = Dim.Percent (40),
             Source = new ListWrapper<string> (items)
         };
-        listview.SelectedItemChanged += (s, e) => lbListView.Text = items [listview.SelectedItem];
+        listview.SelectedItemChanged += (s, e) => lbListView.Text = items [listview.SelectedItem.Value];
         win.Add (lbListView, listview);
 
         //var scrollBar = new ScrollBarView (listview, true);
@@ -91,7 +91,7 @@ public class ListsAndCombos : Scenario
         // ComboBox
         var lbComboBox = new Label
         {
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             X = Pos.Right (lbListView) + 1,
 
             Width = Dim.Percent (40),

+ 92 - 77
Examples/UICatalog/Scenarios/Localization.cs

@@ -1,7 +1,6 @@
-using System;
+#nullable enable
+
 using System.Globalization;
-using System.Linq;
-using System.Threading;
 
 namespace UICatalog.Scenarios;
 
@@ -10,11 +9,11 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Tests")]
 public class Localization : Scenario
 {
-    private CheckBox _allowAnyCheckBox;
-    private string [] _cultureInfoNameSource;
-    private CultureInfo [] _cultureInfoSource;
+    private CheckBox? _allowAnyCheckBox;
+    private string []? _cultureInfoNameSource;
+    private CultureInfo []? _cultureInfoSource;
     private OpenMode _currentOpenMode = OpenMode.File;
-    private ComboBox _languageComboBox;
+    private ComboBox? _languageComboBox;
     public CultureInfo CurrentCulture { get; private set; } = Thread.CurrentThread.CurrentUICulture;
 
     public void Quit ()
@@ -25,6 +24,11 @@ public class Localization : Scenario
 
     public void SetCulture (CultureInfo culture)
     {
+        if (_languageComboBox is null || _cultureInfoSource is null)
+        {
+            return;
+        }
+
         if (_cultureInfoSource [_languageComboBox.SelectedItem] != culture)
         {
             _languageComboBox.SelectedItem = Array.IndexOf (_cultureInfoSource, culture);
@@ -43,70 +47,67 @@ public class Localization : Scenario
     public override void Main ()
     {
         Application.Init ();
-        var top = new Toplevel ();
-        var win = new Window { Title = GetQuitKeyAndName () };
-        _cultureInfoSource = Application.SupportedCultures.Append (CultureInfo.InvariantCulture).ToArray ();
 
-        _cultureInfoNameSource = Application.SupportedCultures.Select (c => $"{c.NativeName} ({c.Name})")
+        Window win = new ()
+        {
+            Title = GetQuitKeyAndName (),
+            BorderStyle = LineStyle.None
+        };
+
+        _cultureInfoSource = Application.SupportedCultures!.Append (CultureInfo.InvariantCulture).ToArray ();
+
+        _cultureInfoNameSource = Application.SupportedCultures!.Select (c => $"{c.NativeName} ({c.Name})")
                                             .Append ("Invariant")
                                             .ToArray ();
 
-        MenuItem [] languageMenus = Application.SupportedCultures
-                                               .Select (
-                                                        c => new MenuItem (
-                                                                           $"{c.NativeName} ({c.Name})",
-                                                                           "",
-                                                                           () => SetCulture (c)
-                                                                          )
-                                                       )
-                                               .Concat (
-                                                        new MenuItem []
+        MenuItem [] languageMenus = Application.SupportedCultures!
+                                               .Select (c => new MenuItem
                                                         {
-                                                            null,
-                                                            new (
-                                                                 "Invariant",
-                                                                 "",
-                                                                 () =>
-                                                                     SetCulture (
-                                                                                 CultureInfo
-                                                                                     .InvariantCulture
-                                                                                )
-                                                                )
+                                                            Title = $"{c.NativeName} ({c.Name})",
+                                                            Action = () => SetCulture (c)
                                                         }
                                                        )
+                                               .Concat (
+                                                        [
+                                                            new ()
+                                                            {
+                                                                Title = "Invariant",
+                                                                Action = () => SetCulture (CultureInfo.InvariantCulture)
+                                                            }
+                                                        ]
+                                                       )
                                                .ToArray ();
 
-        var menu = new MenuBar
-        {
-            Menus =
-            [
-                new (
-                     "_File",
-                     new MenuItem []
-                     {
-                         new MenuBarItem (
-                                          "_Language",
-                                          languageMenus
-                                         ),
-                         null,
-                         new ("_Quit", "", Quit)
-                     }
-                    )
-            ]
-        };
-        top.Add (menu);
-
-        var selectLanguageLabel = new Label
+        // MenuBar
+        MenuBar menu = new ();
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_File",
+                                   [
+                                       new MenuBarItem (
+                                                        "_Language",
+                                                        languageMenus
+                                                       ),
+                                       new MenuItem
+                                       {
+                                           Title = "_Quit",
+                                           Action = Quit
+                                       }
+                                   ]
+                                  )
+                 );
+
+        Label selectLanguageLabel = new ()
         {
             X = 2,
-            Y = 1,
-
+            Y = Pos.Bottom (menu) + 1,
             Width = Dim.Fill (2),
             Text = "Please select a language."
         };
         win.Add (selectLanguageLabel);
 
-        _languageComboBox = new()
+        _languageComboBox = new ()
         {
             X = 2,
             Y = Pos.Bottom (selectLanguageLabel) + 1,
@@ -120,11 +121,10 @@ public class Localization : Scenario
         _languageComboBox.SelectedItemChanged += LanguageComboBox_SelectChanged;
         win.Add (_languageComboBox);
 
-        var textAndFileDialogLabel = new Label
+        Label textAndFileDialogLabel = new ()
         {
             X = 2,
             Y = Pos.Top (_languageComboBox) + 3,
-
             Width = Dim.Fill (2),
             Height = 1,
             Text =
@@ -132,13 +132,16 @@ public class Localization : Scenario
         };
         win.Add (textAndFileDialogLabel);
 
-        var textField = new TextView
+        TextView textField = new ()
         {
-            X = 2, Y = Pos.Bottom (textAndFileDialogLabel) + 1, Width = Dim.Fill (32), Height = 1
+            X = 2,
+            Y = Pos.Bottom (textAndFileDialogLabel) + 1,
+            Width = Dim.Fill (32),
+            Height = 1
         };
         win.Add (textField);
 
-        _allowAnyCheckBox = new()
+        _allowAnyCheckBox = new ()
         {
             X = Pos.Right (textField) + 1,
             Y = Pos.Bottom (textAndFileDialogLabel) + 1,
@@ -147,46 +150,53 @@ public class Localization : Scenario
         };
         win.Add (_allowAnyCheckBox);
 
-        var openDialogButton = new Button
+        Button openDialogButton = new ()
         {
-            X = Pos.Right (_allowAnyCheckBox) + 1, Y = Pos.Bottom (textAndFileDialogLabel) + 1, Text = "Open"
+            X = Pos.Right (_allowAnyCheckBox) + 1,
+            Y = Pos.Bottom (textAndFileDialogLabel) + 1,
+            Text = "Open"
         };
         openDialogButton.Accepting += (sender, e) => ShowFileDialog (false);
         win.Add (openDialogButton);
 
-        var saveDialogButton = new Button
+        Button saveDialogButton = new ()
         {
-            X = Pos.Right (openDialogButton) + 1, Y = Pos.Bottom (textAndFileDialogLabel) + 1, Text = "Save"
+            X = Pos.Right (openDialogButton) + 1,
+            Y = Pos.Bottom (textAndFileDialogLabel) + 1,
+            Text = "Save"
         };
         saveDialogButton.Accepting += (sender, e) => ShowFileDialog (true);
         win.Add (saveDialogButton);
 
-        var wizardLabel = new Label
+        Label wizardLabel = new ()
         {
             X = 2,
             Y = Pos.Bottom (textField) + 1,
-
             Width = Dim.Fill (2),
             Text = "Click the button to open a wizard."
         };
         win.Add (wizardLabel);
 
-        var wizardButton = new Button { X = 2, Y = Pos.Bottom (wizardLabel) + 1, Text = "Open _wizard" };
+        Button wizardButton = new () { X = 2, Y = Pos.Bottom (wizardLabel) + 1, Text = "Open _wizard" };
         wizardButton.Accepting += (sender, e) => ShowWizard ();
         win.Add (wizardButton);
 
-        win.Unloaded += (sender, e) => Quit ();
+        win.IsRunningChanged += (sender, e) => Quit ();
 
-        win.Y = Pos.Bottom (menu);
-        top.Add (win);
+        win.Add (menu);
 
-        Application.Run (top);
-        top.Dispose ();
+        Application.Run (win);
+        win.Dispose ();
         Application.Shutdown ();
     }
 
     public void ShowFileDialog (bool isSaveFile)
     {
+        if (_allowAnyCheckBox is null)
+        {
+            return;
+        }
+
         FileDialog dialog = isSaveFile ? new SaveDialog () : new OpenDialog { OpenMode = _currentOpenMode };
 
         dialog.AllowedTypes =
@@ -213,16 +223,21 @@ public class Localization : Scenario
 
     public void ShowWizard ()
     {
-        var wizard = new Wizard { Height = 8, Width = 36, Title = "The wizard" };
-        wizard.AddStep (new() { HelpText = "Wizard first step" });
-        wizard.AddStep (new() { HelpText = "Wizard step 2", NextButtonText = ">>> (_N)" });
-        wizard.AddStep (new() { HelpText = "Wizard last step" });
+        Wizard wizard = new () { Height = 8, Width = 36, Title = "The wizard" };
+        wizard.AddStep (new () { HelpText = "Wizard first step" });
+        wizard.AddStep (new () { HelpText = "Wizard step 2", NextButtonText = ">>> (_N)" });
+        wizard.AddStep (new () { HelpText = "Wizard last step" });
         Application.Run (wizard);
         wizard.Dispose ();
     }
 
-    private void LanguageComboBox_SelectChanged (object sender, ListViewItemEventArgs e)
+    private void LanguageComboBox_SelectChanged (object? sender, ListViewItemEventArgs e)
     {
+        if (_cultureInfoNameSource is null || _cultureInfoSource is null)
+        {
+            return;
+        }
+
         if (e.Value is string cultureName)
         {
             int index = Array.IndexOf (_cultureInfoNameSource, cultureName);

+ 8 - 8
Examples/UICatalog/Scenarios/Mazing.cs

@@ -9,7 +9,7 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Games")]
 public class Mazing : Scenario
 {
-    private Toplevel? _top;
+    private Window? _top;
     private MazeGenerator? _m;
 
     private List<Point>? _potions;
@@ -33,17 +33,17 @@ public class Mazing : Scenario
         _top.KeyBindings.Add (Key.CursorDown, Command.Down);
 
         // Changing the key-bindings of a View is not allowed, however,
-        // by default, Toplevel doesn't bind any of our movement keys, so
+        // by default, Runnable doesn't bind any of our movement keys, so
         // we can take advantage of the CommandNotBound event to handle them
         // 
-        // An alternative implementation would be to create a TopLevel subclass that
+        // An alternative implementation would be to create a Runnable subclass that
         // calls AddCommand/KeyBindings.Add in the constructor. See the Snake game scenario
         // for an example.
         _top.CommandNotBound += TopCommandNotBound;
 
         _top.DrawingContent += (s, _) =>
                                {
-                                   if (s is not Toplevel top)
+                                   if (s is not Runnable top)
                                    {
                                        return;
                                    }
@@ -129,7 +129,7 @@ public class Mazing : Scenario
             return;
         }
 
-        Point newPos = _m.Player;
+        Point newPos = _m!.Player;
 
         Command? command = e.Context?.Command;
 
@@ -171,7 +171,7 @@ public class Mazing : Scenario
                 if (_m.PlayerHp <= 0)
                 {
                     _message = "You died!";
-                    Application.Top!.SetNeedsDraw (); // trigger redraw
+                    Application.TopRunnableView!.SetNeedsDraw (); // trigger redraw
                     _dead = true;
 
                     return; // Stop further action if dead
@@ -190,7 +190,7 @@ public class Mazing : Scenario
                 _message = string.Empty;
             }
 
-            Application.Top!.SetNeedsDraw (); // trigger redraw
+            Application.TopRunnableView!.SetNeedsDraw (); // trigger redraw
         }
 
         // Optional win condition:
@@ -200,7 +200,7 @@ public class Mazing : Scenario
             _m = new (); // Generate a new maze
             _m.PlayerHp = hp;
             GenerateNpcs ();
-            Application.Top!.SetNeedsDraw (); // trigger redraw
+            Application.TopRunnableView!.SetNeedsDraw (); // trigger redraw
         }
     }
 }

+ 0 - 135
Examples/UICatalog/Scenarios/MenuBarScenario.cs

@@ -1,135 +0,0 @@
-using System;
-using static System.Runtime.InteropServices.JavaScript.JSType;
-
-namespace UICatalog.Scenarios;
-
-[ScenarioMetadata ("MenuBar", "Demonstrates the MenuBar using the demo menu.")]
-[ScenarioCategory ("Controls")]
-[ScenarioCategory ("Menus")]
-public class MenuBarScenario : Scenario
-{
-    private Label _currentMenuBarItem;
-    private Label _currentMenuItem;
-    private Label _focusedView;
-    private Label _lastAction;
-    private Label _lastKey;
-
-    public override void Main ()
-    {
-        // Init
-        Application.Init ();
-
-        // Setup - Create a top-level application window and configure it.
-        Window appWindow = new ()
-        {
-            Title = GetQuitKeyAndName (),
-            BorderStyle = LineStyle.None
-        };
-
-        MenuItem mbiCurrent = null;
-        MenuItem miCurrent = null;
-
-        var label = new Label { X = 0, Y = 10, Text = "Last Key: " };
-        appWindow.Add (label);
-
-        _lastKey = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
-
-        appWindow.Add (_lastKey);
-        label = new Label { X = 0, Y = Pos.Bottom (label), Text = "Current MenuBarItem: " };
-        appWindow.Add (label);
-
-        _currentMenuBarItem = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
-        appWindow.Add (_currentMenuBarItem);
-
-        label = new Label { X = 0, Y = Pos.Bottom (label), Text = "Current MenuItem: " };
-        appWindow.Add (label);
-
-        _currentMenuItem = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
-        appWindow.Add (_currentMenuItem);
-
-        label = new Label { X = 0, Y = Pos.Bottom (label), Text = "Last Action: " };
-        appWindow.Add (label);
-
-        _lastAction = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
-        appWindow.Add (_lastAction);
-
-        label = new Label { X = 0, Y = Pos.Bottom (label), Text = "Focused View: " };
-        appWindow.Add (label);
-
-        _focusedView = new Label { X = Pos.Right (label), Y = Pos.Top (label), Text = "" };
-        appWindow.Add (_focusedView);
-
-        MenuBar menuBar = new MenuBar ();
-        menuBar.UseKeysUpDownAsKeysLeftRight = true;
-        menuBar.Key = KeyCode.F9;
-        menuBar.Title = "TestMenuBar";
-
-        bool FnAction (string s)
-        {
-            _lastAction.Text = s;
-
-            return true;
-        }
-        
-        // Declare a variable for the function
-        Func<string, bool> fnActionVariable = FnAction;
-
-        menuBar.EnableForDesign (ref fnActionVariable);
-
-        menuBar.MenuOpening += (s, e) =>
-                               {
-                                   mbiCurrent = e.CurrentMenu;
-                                   SetCurrentMenuBarItem (mbiCurrent);
-                                   SetCurrentMenuItem (miCurrent);
-                                   _lastAction.Text = string.Empty;
-                               };
-
-        menuBar.MenuOpened += (s, e) =>
-                              {
-                                  miCurrent = e.MenuItem;
-                                  SetCurrentMenuBarItem (mbiCurrent);
-                                  SetCurrentMenuItem (miCurrent);
-                              };
-
-        menuBar.MenuClosing += (s, e) =>
-                               {
-                                   mbiCurrent = null;
-                                   miCurrent = null;
-                                   SetCurrentMenuBarItem (mbiCurrent);
-                                   SetCurrentMenuItem (miCurrent);
-                               };
-
-        Application.KeyDown += (s, e) =>
-                               {
-                                   _lastAction.Text = string.Empty;
-                                   _lastKey.Text = e.ToString ();
-                               };
-
-        // There's no focus change event, so this is a bit of a hack.
-        menuBar.SubViewsLaidOut += (s, e) => { _focusedView.Text = appWindow.MostFocused?.ToString () ?? "None"; };
-
-        var openBtn = new Button { X = Pos.Center (), Y = 4, Text = "_Open Menu", IsDefault = true };
-        openBtn.Accepting += (s, e) => { menuBar.OpenMenu (); };
-        appWindow.Add (openBtn);
-
-        var hideBtn = new Button { X = Pos.Center (), Y = Pos.Bottom (openBtn), Text = "Toggle Menu._Visible" };
-        hideBtn.Accepting += (s, e) => { menuBar.Visible = !menuBar.Visible; };
-        appWindow.Add (hideBtn);
-
-        var enableBtn = new Button { X = Pos.Center (), Y = Pos.Bottom (hideBtn), Text = "_Toggle Menu.Enable" };
-        enableBtn.Accepting += (s, e) => { menuBar.Enabled = !menuBar.Enabled; };
-        appWindow.Add (enableBtn);
-
-        appWindow.Add (menuBar);
-
-        // Run - Start the application.
-        Application.Run (appWindow);
-        appWindow.Dispose ();
-
-        // Shutdown - Calling Application.Shutdown is required.
-        Application.Shutdown ();
-    }
-
-    private void SetCurrentMenuBarItem (MenuItem mbi) { _currentMenuBarItem.Text = mbi != null ? mbi.Title : "Closed"; }
-    private void SetCurrentMenuItem (MenuItem mi) { _currentMenuItem.Text = mi != null ? mi.Title : "None"; }
-}

+ 6 - 6
Examples/UICatalog/Scenarios/Menus.cs

@@ -21,7 +21,7 @@ public class Menus : Scenario
         Logging.Logger = CreateLogger ();
 
         Application.Init ();
-        Toplevel app = new ();
+        Runnable app = new ();
         app.Title = GetQuitKeyAndName ();
 
         ObservableCollection<string> eventSource = new ();
@@ -32,7 +32,7 @@ public class Menus : Scenario
             X = Pos.AnchorEnd (),
             Width = Dim.Auto (),
             Height = Dim.Fill (), // Make room for some wide things
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (eventSource)
         };
         eventLog.Border!.Thickness = new (0, 1, 0, 0);
@@ -121,7 +121,7 @@ public class Menus : Scenario
                         Command.Cancel,
                         ctx =>
                         {
-                            if (Application.Popover?.GetActivePopover () as PopoverMenu is { Visible: true } visiblePopover)
+                            if (App?.Popover?.GetActivePopover () as PopoverMenu is { Visible: true } visiblePopover)
                             {
                                 visiblePopover.Visible = false;
                             }
@@ -189,7 +189,7 @@ public class Menus : Scenario
             Application.KeyBindings.Remove (Key.F5);
             Application.KeyBindings.Add (Key.F5, this, Command.Edit);
 
-            var menuBar = new MenuBarv2
+            var menuBar = new MenuBar
             {
                 Title = "MenuHost MenuBar"
             };
@@ -257,7 +257,7 @@ public class Menus : Scenario
 
             menuBar.Accepted += (o, args) =>
                                 {
-                                    if (args.Context?.Source is MenuItemv2 mi && mi.CommandView == enableOverwriteMenuItemCb)
+                                    if (args.Context?.Source is MenuItem mi && mi.CommandView == enableOverwriteMenuItemCb)
                                     {
                                         Logging.Debug ($"menuBar.Accepted: {args.Context.Source?.Title}");
 
@@ -302,7 +302,7 @@ public class Menus : Scenario
 
             menuBar.Accepted += (o, args) =>
                                 {
-                                    if (args.Context?.Source is MenuItemv2 mi && mi.CommandView == editModeMenuItemCb)
+                                    if (args.Context?.Source is MenuItem mi && mi.CommandView == editModeMenuItemCb)
                                     {
                                         Logging.Debug ($"menuBar.Accepted: {args.Context.Source?.Title}");
 

+ 18 - 17
Examples/UICatalog/Scenarios/MessageBoxes.cs

@@ -182,18 +182,19 @@ public class MessageBoxes : Scenario
         };
         frame.Add (label);
 
-        var styleRadioGroup = new RadioGroup
+        var styleOptionSelector = new OptionSelector ()
         {
-            X = Pos.Right (label) + 1, 
-            Y = Pos.Top (label), 
-            RadioLabels = ["_Query", "_Error"],
+            X = Pos.Right (label) + 1,
+            Y = Pos.Top (label),
+            Labels = ["_Query", "_Error"],
+            Title = "Sty_le"
         };
-        frame.Add (styleRadioGroup);
+        frame.Add (styleOptionSelector);
 
         label = new ()
         {
             X = 0,
-            Y = Pos.Bottom (styleRadioGroup),
+            Y = Pos.Bottom (styleOptionSelector),
 
             Width = Dim.Width (label),
             Height = 1,
@@ -202,7 +203,7 @@ public class MessageBoxes : Scenario
         };
         var ckbWrapMessage = new CheckBox
         {
-            X = Pos.Right (label) + 1, Y = Pos.Bottom (styleRadioGroup),
+            X = Pos.Right (label) + 1, Y = Pos.Bottom (styleOptionSelector),
             CheckedState = CheckState.Checked,
             Text = "_Wrap Message",
         };
@@ -246,11 +247,11 @@ public class MessageBoxes : Scenario
                                                    btns.Add ($"_{NumberToWords.Convert (i)}");
                                                }
 
-                                               if (styleRadioGroup.SelectedItem == 0)
+                                               if (styleOptionSelector.Value == 0)
                                                {
                                                    buttonPressedLabel.Text =
                                                        $"{MessageBox.Query (
-                                                                             width,
+                                                                            ApplicationImpl.Instance, width,
                                                                              height,
                                                                              titleEdit.Text,
                                                                              messageEdit.Text,
@@ -262,14 +263,14 @@ public class MessageBoxes : Scenario
                                                else
                                                {
                                                    buttonPressedLabel.Text =
-                                                       $"{MessageBox.ErrorQuery (
-                                                                                  width,
-                                                                                  height,
-                                                                                  titleEdit.Text,
-                                                                                  messageEdit.Text,
-                                                                                  defaultButton,
-                                                                                  ckbWrapMessage.CheckedState == CheckState.Checked,
-                                                                                  btns.ToArray ()
+                                                       $"{MessageBox.ErrorQuery (ApplicationImpl.Instance,
+                                                                                 width,
+                                                                                 height,
+                                                                                 titleEdit.Text,
+                                                                                 messageEdit.Text,
+                                                                                 defaultButton,
+                                                                                 ckbWrapMessage.CheckedState == CheckState.Checked,
+                                                                                 btns.ToArray ()
                                                                                  )}";
                                                }
                                            }

+ 2 - 2
Examples/UICatalog/Scenarios/Mouse.cs

@@ -247,7 +247,7 @@ public class Mouse : Scenario
             Y = Pos.Bottom (label),
             Width = 50,
             Height = Dim.Fill (),
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (appLogList)
         };
         win.Add (label, appLog);
@@ -278,7 +278,7 @@ public class Mouse : Scenario
             Y = Pos.Bottom (label),
             Width = Dim.Percent (50),
             Height = Dim.Fill (),
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (winLogList)
         };
         win.Add (label, winLog);

+ 82 - 73
Examples/UICatalog/Scenarios/MultiColouredTable.cs

@@ -1,4 +1,5 @@
-using System;
+#nullable enable
+
 using System.Data;
 using System.Text;
 
@@ -10,40 +11,49 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("TableView")]
 public class MultiColouredTable : Scenario
 {
-    private DataTable _table;
-    private TableViewColors _tableView;
+    private DataTable? _table;
+    private TableViewColors? _tableView;
 
     public override void Main ()
     {
-        // Init
         Application.Init ();
 
-        // Setup - Create a top-level application window and configure it.
-        Toplevel appWindow = new ()
-        {
-            Title = GetQuitKeyAndName ()
-        };
-
-        _tableView = new () { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill (1) };
-
-        var menu = new MenuBar
+        Window appWindow = new ()
         {
-            Menus =
-            [
-                new ("_File", new MenuItem [] { new ("_Quit", "", Quit) })
-            ]
+            Title = GetQuitKeyAndName (),
+            BorderStyle = LineStyle.None,
         };
-        appWindow.Add (menu);
 
-        var statusBar = new StatusBar (new Shortcut [] { new (Application.QuitKey, "Quit", Quit) });
-
-        appWindow.Add (statusBar);
-
-        appWindow.Add (_tableView);
+        // MenuBar
+        var menu = new MenuBar ();
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_File",
+                                   [
+                                       new MenuItem
+                                       {
+                                           Title = "_Quit",
+                                           Action = Quit
+                                       }
+                                   ]
+                                  )
+                 );
+
+        _tableView = new () { X = 0, Y = Pos.Bottom (menu), Width = Dim.Fill (), Height = Dim.Fill (1) };
+
+        // StatusBar
+        var statusBar = new StatusBar (
+                                       [
+                                           new (Application.QuitKey, "Quit", Quit)
+                                       ]
+                                      );
+
+        appWindow.Add (menu, _tableView, statusBar);
 
         _tableView.CellActivated += EditCurrentCell;
 
-        var dt = new DataTable ();
+        DataTable dt = new ();
         dt.Columns.Add ("Col1");
         dt.Columns.Add ("Col2");
 
@@ -54,34 +64,33 @@ public class MultiColouredTable : Scenario
         dt.Rows.Add (DBNull.Value, DBNull.Value);
         dt.Rows.Add (DBNull.Value, DBNull.Value);
 
-        _tableView.SetScheme (new ()
-        {
-            Disabled = appWindow.GetAttributeForRole (VisualRole.Disabled),
-            HotFocus = appWindow.GetAttributeForRole (VisualRole.HotFocus),
-            Focus = appWindow.GetAttributeForRole (VisualRole.Focus),
-            Normal = new (Color.DarkGray, Color.Black)
-        });
+        _tableView.SetScheme (
+                              new ()
+                              {
+                                  Disabled = appWindow.GetAttributeForRole (VisualRole.Disabled),
+                                  HotFocus = appWindow.GetAttributeForRole (VisualRole.HotFocus),
+                                  Focus = appWindow.GetAttributeForRole (VisualRole.Focus),
+                                  Normal = new (Color.DarkGray, Color.Black)
+                              }
+                             );
 
         _tableView.Table = new DataTableSource (_table = dt);
 
-        // Run - Start the application.
         Application.Run (appWindow);
         appWindow.Dispose ();
-
-        // Shutdown - Calling Application.Shutdown is required.
         Application.Shutdown ();
     }
 
-    private void EditCurrentCell (object sender, CellActivatedEventArgs e)
+    private void EditCurrentCell (object? sender, CellActivatedEventArgs e)
     {
-        if (e.Table == null)
+        if (e.Table is null || _table is null || _tableView is null)
         {
             return;
         }
 
         var oldValue = e.Table [e.Row, e.Col].ToString ();
 
-        if (GetText ("Enter new value", e.Table.ColumnNames [e.Col], oldValue, out string newText))
+        if (GetText ("Enter new value", e.Table.ColumnNames [e.Col], oldValue ?? "", out string newText))
         {
             try
             {
@@ -90,7 +99,7 @@ public class MultiColouredTable : Scenario
             }
             catch (Exception ex)
             {
-                MessageBox.ErrorQuery (60, 20, "Failed to set text", ex.Message, "Ok");
+                MessageBox.ErrorQuery (ApplicationImpl.Instance, 60, 20, "Failed to set text", ex.Message, "Ok");
             }
 
             _tableView.Update ();
@@ -101,20 +110,20 @@ public class MultiColouredTable : Scenario
     {
         var okPressed = false;
 
-        var ok = new Button { Text = "Ok", IsDefault = true };
+        Button ok = new () { Text = "Ok", IsDefault = true };
 
         ok.Accepting += (s, e) =>
-                     {
-                         okPressed = true;
-                         Application.RequestStop ();
-                     };
-        var cancel = new Button { Text = "Cancel" };
+                        {
+                            okPressed = true;
+                            Application.RequestStop ();
+                        };
+        Button cancel = new () { Text = "Cancel" };
         cancel.Accepting += (s, e) => { Application.RequestStop (); };
-        var d = new Dialog { Title = title, Buttons = [ok, cancel] };
+        Dialog d = new () { Title = title, Buttons = [ok, cancel] };
 
-        var lbl = new Label { X = 0, Y = 1, Text = label };
+        Label lbl = new () { X = 0, Y = 1, Text = label };
 
-        var tf = new TextField { Text = initialText, X = 0, Y = 2, Width = Dim.Fill () };
+        TextField tf = new () { Text = initialText, X = 0, Y = 2, Width = Dim.Fill () };
 
         d.Add (lbl, tf);
         tf.SetFocus ();
@@ -122,7 +131,7 @@ public class MultiColouredTable : Scenario
         Application.Run (d);
         d.Dispose ();
 
-        enteredText = okPressed ? tf.Text : null;
+        enteredText = okPressed ? tf.Text : string.Empty;
 
         return okPressed;
     }
@@ -155,20 +164,20 @@ public class MultiColouredTable : Scenario
                             break;
                         case 1:
                             SetAttribute (
-                                                 new (
-                                                      Color.BrightRed,
-                                                      cellColor.Background
-                                                     )
-                                                );
+                                          new (
+                                               Color.BrightRed,
+                                               cellColor.Background
+                                              )
+                                         );
 
                             break;
                         case 2:
                             SetAttribute (
-                                                 new (
-                                                      Color.BrightYellow,
-                                                      cellColor.Background
-                                                     )
-                                                );
+                                          new (
+                                               Color.BrightYellow,
+                                               cellColor.Background
+                                              )
+                                         );
 
                             break;
                         case 3:
@@ -177,29 +186,29 @@ public class MultiColouredTable : Scenario
                             break;
                         case 4:
                             SetAttribute (
-                                                 new (
-                                                      Color.BrightGreen,
-                                                      cellColor.Background
-                                                     )
-                                                );
+                                          new (
+                                               Color.BrightGreen,
+                                               cellColor.Background
+                                              )
+                                         );
 
                             break;
                         case 5:
                             SetAttribute (
-                                                 new (
-                                                      Color.BrightBlue,
-                                                      cellColor.Background
-                                                     )
-                                                );
+                                          new (
+                                               Color.BrightBlue,
+                                               cellColor.Background
+                                              )
+                                         );
 
                             break;
                         case 6:
                             SetAttribute (
-                                                 new (
-                                                      Color.BrightCyan,
-                                                      cellColor.Background
-                                                     )
-                                                );
+                                          new (
+                                               Color.BrightCyan,
+                                               cellColor.Background
+                                              )
+                                         );
 
                             break;
                         case 7:

+ 17 - 15
Examples/UICatalog/Scenarios/Navigation.cs

@@ -59,7 +59,7 @@ public class Navigation : Scenario
             Y = 0,
             Title = $"TopButton _{GetNextHotKey ()}"
         };
-        button.Accepting += (sender, args) => MessageBox.Query ("hi", button.Title, "_Ok");
+        button.Accepting += (sender, args) => MessageBox.Query (ApplicationImpl.Instance, "hi", button.Title, "_Ok");
 
         testFrame.Add (button);
 
@@ -107,18 +107,7 @@ public class Navigation : Scenario
         //                 };
         //timer.Start ();
 
-        Application.Iteration += (sender, args) =>
-                                 {
-                                     if (progressBar.Fraction == 1.0)
-                                     {
-                                         progressBar.Fraction = 0;
-                                     }
-
-                                     progressBar.Fraction += 0.01f;
-
-                                     Application.Invoke (() => { });
-
-                                 };
+        Application.Iteration += OnApplicationIteration;
 
         View overlappedView2 = CreateOverlappedView (3, 8, 10);
 
@@ -191,7 +180,7 @@ public class Navigation : Scenario
             X = 1,
             Y = 7,
             Id = "datePicker",
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             ShadowStyle = ShadowStyle.Transparent,
             BorderStyle = LineStyle.Double,
             CanFocus = true, // Can't drag without this? BUGBUG
@@ -214,12 +203,25 @@ public class Navigation : Scenario
 
         testFrame.SetFocus ();
         Application.Run (app);
+        Application.Iteration -= OnApplicationIteration;
         // timer.Close ();
         app.Dispose ();
         Application.Shutdown ();
 
         return;
 
+        void OnApplicationIteration (object sender, EventArgs<IApplication> args)
+        {
+            if (progressBar.Fraction == 1.0)
+            {
+                progressBar.Fraction = 0;
+            }
+
+            progressBar.Fraction += 0.01f;
+
+            Application.Invoke ((_) => { });
+        }
+
         void ColorPicker_ColorChanged (object sender, ResultEventArgs<Color> e)
         {
             testFrame.SetScheme (testFrame.GetScheme () with { Normal = new (testFrame.GetAttributeForRole (VisualRole.Normal).Foreground, e.Result) });
@@ -235,7 +237,7 @@ public class Navigation : Scenario
             Height = Dim.Auto (),
             Width = Dim.Auto (),
             Title = $"Overlapped{id} _{GetNextHotKey ()}",
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Id = $"Overlapped{id}",
             ShadowStyle = ShadowStyle.Transparent,
             BorderStyle = LineStyle.Double,

+ 166 - 119
Examples/UICatalog/Scenarios/Notepad.cs

@@ -1,5 +1,4 @@
-using System.IO;
-using System.Linq;
+#nullable enable
 
 namespace UICatalog.Scenarios;
 
@@ -9,50 +8,74 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("TextView")]
 public class Notepad : Scenario
 {
-    private TabView _focusedTabView;
-    public Shortcut LenShortcut { get; private set; }
+    private TabView? _focusedTabView;
     private int _numNewTabs = 1;
-    private TabView _tabView;
+    private TabView? _tabView;
+    public Shortcut? LenShortcut { get; private set; }
 
     public override void Main ()
     {
         Application.Init ();
 
-        Toplevel top = new ();
-
-        var menu = new MenuBar
+        Window top = new ()
         {
-            Menus =
-            [
-                new (
-                     "_File",
-                     new MenuItem []
-                     {
-                         new (
-                              "_New",
-                              "",
-                              () => New (),
-                              null,
-                              null,
-                              KeyCode.N
-                              | KeyCode.CtrlMask
-                              | KeyCode.AltMask
-                             ),
-                         new ("_Open", "", Open),
-                         new ("_Save", "", Save),
-                         new ("Save _As", "", () => SaveAs ()),
-                         new ("_Close", "", Close),
-                         new ("_Quit", "", Quit)
-                     }
-                    ),
-                new (
-                     "_About",
-                     "",
-                     () => MessageBox.Query ("Notepad", "About Notepad...", "Ok")
-                    )
-            ]
+            BorderStyle = LineStyle.None,
         };
-        top.Add (menu);
+
+        // MenuBar
+        MenuBar menu = new ();
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_File",
+                                   [
+                                       new MenuItem
+                                       {
+                                           Title = "_New",
+                                           Key = Key.N.WithCtrl.WithAlt,
+                                           Action = New
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Open",
+                                           Action = Open
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Save",
+                                           Action = Save
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "Save _As",
+                                           Action = () => SaveAs ()
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Close",
+                                           Action = Close
+                                       },
+                                       new MenuItem
+                                       {
+                                           Title = "_Quit",
+                                           Action = Quit
+                                       }
+                                   ]
+                                  )
+                 );
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_About",
+                                   [
+                                       new MenuItem
+                                       {
+                                           Title = "_About",
+                                           Action = () => MessageBox.Query (ApplicationImpl.Instance,  "Notepad", "About Notepad...", "Ok")
+                                       }
+                                   ]
+                                  )
+                 );
 
         _tabView = CreateNewTabView ();
 
@@ -60,83 +83,85 @@ public class Notepad : Scenario
         _tabView.ApplyStyleChanges ();
 
         _tabView.X = 0;
-        _tabView.Y = 1;
+        _tabView.Y = Pos.Bottom (menu);
         _tabView.Width = Dim.Fill ();
         _tabView.Height = Dim.Fill (1);
 
-        top.Add (_tabView);
         LenShortcut = new (Key.Empty, "Len: ", null);
 
-        var statusBar = new StatusBar (new [] {
-                                           new (Application.QuitKey, $"Quit", Quit),
-                                           new Shortcut(Key.F2, "Open", Open),
-                                           new Shortcut(Key.F1, "New", New),
-                                           new (Key.F3, "Save", Save),
-                                           new (Key.F6, "Close", Close),
-                                           LenShortcut
-                                       }
-                                      )
+        // StatusBar
+        StatusBar statusBar = new (
+                                   [
+                                       new (Application.QuitKey, "Quit", Quit),
+                                       new (Key.F2, "Open", Open),
+                                       new (Key.F1, "New", New),
+                                       new (Key.F3, "Save", Save),
+                                       new (Key.F6, "Close", Close),
+                                       LenShortcut
+                                   ]
+                                  )
         {
             AlignmentModes = AlignmentModes.IgnoreFirstOrLast
         };
-        top.Add (statusBar);
+
+        top.Add (menu, _tabView, statusBar);
 
         _focusedTabView = _tabView;
         _tabView.SelectedTabChanged += TabView_SelectedTabChanged;
         _tabView.HasFocusChanging += (s, e) => _focusedTabView = _tabView;
 
-        top.Ready += (s, e) =>
+        top.IsModalChanged += (s, e) =>
                      {
-                         New ();
-                         LenShortcut.Title = $"Len:{_focusedTabView.Text?.Length ?? 0}";
+                         if (e.Value)
+                         {
+                             New ();
+                             LenShortcut.Title = $"Len:{_focusedTabView?.Text?.Length ?? 0}";
+                         }
                      };
 
         Application.Run (top);
         top.Dispose ();
-
         Application.Shutdown ();
     }
 
-    public void Save () { Save (_focusedTabView, _focusedTabView.SelectedTab); }
+    public void Save ()
+    {
+        if (_focusedTabView?.SelectedTab is { })
+        {
+            Save (_focusedTabView, _focusedTabView.SelectedTab);
+        }
+    }
 
     public void Save (TabView tabViewToSave, Tab tabToSave)
     {
-        var tab = tabToSave as OpenedFile;
-
-        if (tab == null)
+        if (tabToSave is not OpenedFile tab)
         {
             return;
         }
 
-        if (tab.File == null)
+        if (tab.File is null)
         {
             SaveAs ();
         }
+        else
+        {
+            tab.Save ();
+        }
 
-        tab.Save ();
         tabViewToSave.SetNeedsDraw ();
     }
 
     public bool SaveAs ()
     {
-        var tab = _focusedTabView.SelectedTab as OpenedFile;
-
-        if (tab == null)
+        if (_focusedTabView?.SelectedTab is not OpenedFile tab)
         {
             return false;
         }
 
-        var fd = new SaveDialog ();
+        SaveDialog fd = new ();
         Application.Run (fd);
 
-        if (string.IsNullOrWhiteSpace (fd.Path))
-        {
-            fd.Dispose ();
-
-            return false;
-        }
-
-        if (fd.Canceled)
+        if (string.IsNullOrWhiteSpace (fd.Path) || fd.Canceled)
         {
             fd.Dispose ();
 
@@ -152,13 +177,17 @@ public class Notepad : Scenario
         return true;
     }
 
-    private void Close () { Close (_focusedTabView, _focusedTabView.SelectedTab); }
+    private void Close ()
+    {
+        if (_focusedTabView?.SelectedTab is { })
+        {
+            Close (_focusedTabView, _focusedTabView.SelectedTab);
+        }
+    }
 
     private void Close (TabView tv, Tab tabToClose)
     {
-        var tab = tabToClose as OpenedFile;
-
-        if (tab == null)
+        if (tabToClose is not OpenedFile tab)
         {
             return;
         }
@@ -167,15 +196,15 @@ public class Notepad : Scenario
 
         if (tab.UnsavedChanges)
         {
-            int result = MessageBox.Query (
-                                           "Save Changes",
-                                           $"Save changes to {tab.Text.TrimEnd ('*')}",
-                                           "Yes",
-                                           "No",
-                                           "Cancel"
+            int? result = MessageBox.Query (ApplicationImpl.Instance,
+                                            "Save Changes",
+                                            $"Save changes to {tab.Text.TrimEnd ('*')}",
+                                            "Yes",
+                                            "No",
+                                            "Cancel"
                                           );
 
-            if (result == -1 || result == 2)
+            if (result is null || result == 2)
             {
                 // user cancelled
                 return;
@@ -183,7 +212,7 @@ public class Notepad : Scenario
 
             if (result == 0)
             {
-                if (tab.File == null)
+                if (tab.File is null)
                 {
                     SaveAs ();
                 }
@@ -196,7 +225,7 @@ public class Notepad : Scenario
 
         // close and dispose the tab
         tv.RemoveTab (tab);
-        tab.View.Dispose ();
+        tab.View?.Dispose ();
         _focusedTabView = tv;
 
         // If last tab is closed, open a new one
@@ -208,7 +237,7 @@ public class Notepad : Scenario
 
     private TabView CreateNewTabView ()
     {
-        var tv = new TabView { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
+        TabView tv = new () { X = 0, Y = 0, Width = Dim.Fill (), Height = Dim.Fill () };
 
         tv.TabClicked += TabView_TabClicked;
         tv.SelectedTabChanged += TabView_SelectedTabChanged;
@@ -217,11 +246,11 @@ public class Notepad : Scenario
         return tv;
     }
 
-    private void New () { Open (null, $"new {_numNewTabs++}"); }
+    private void New () { Open (null!, $"new {_numNewTabs++}"); }
 
     private void Open ()
     {
-        var open = new OpenDialog { Title = "Open", AllowsMultipleSelection = true };
+        OpenDialog open = new () { Title = "Open", AllowsMultipleSelection = true };
 
         Application.Run (open);
 
@@ -246,9 +275,15 @@ public class Notepad : Scenario
 
     /// <summary>Creates a new tab with initial text</summary>
     /// <param name="fileInfo">File that was read or null if a new blank document</param>
-    private void Open (FileInfo fileInfo, string tabName)
+    /// <param name="tabName"></param>
+    private void Open (FileInfo? fileInfo, string tabName)
     {
-        var tab = new OpenedFile (this) { DisplayText = tabName, File = fileInfo };
+        if (_focusedTabView is null)
+        {
+            return;
+        }
+
+        OpenedFile tab = new (this) { DisplayText = tabName, File = fileInfo };
         tab.View = tab.CreateTextView (fileInfo);
         tab.SavedText = tab.View.Text;
         tab.RegisterTextViewEvents (_focusedTabView);
@@ -258,14 +293,17 @@ public class Notepad : Scenario
 
     private void Quit () { Application.RequestStop (); }
 
-    private void TabView_SelectedTabChanged (object sender, TabChangedEventArgs e)
+    private void TabView_SelectedTabChanged (object? sender, TabChangedEventArgs e)
     {
-        LenShortcut.Title = $"Len:{e.NewTab?.View?.Text?.Length ?? 0}";
+        if (LenShortcut is { })
+        {
+            LenShortcut.Title = $"Len:{e.NewTab?.View?.Text?.Length ?? 0}";
+        }
 
         e.NewTab?.View?.SetFocus ();
     }
 
-    private void TabView_TabClicked (object sender, TabMouseEventArgs e)
+    private void TabView_TabClicked (object? sender, TabMouseEventArgs e)
     {
         // we are only interested in right clicks
         if (!e.MouseEvent.Flags.HasFlag (MouseFlags.Button3Clicked))
@@ -275,39 +313,42 @@ public class Notepad : Scenario
 
         View [] items;
 
-        if (e.Tab == null)
+        if (e.Tab is null)
         {
-            items = [new MenuItemv2 ("Open", "", Open)];
+            items = [new MenuItem { Title = "Open", Action = Open }];
         }
         else
         {
-            var tv = (TabView)sender;
-            var t = (OpenedFile)e.Tab;
+            var tv = (TabView)sender!;
 
             items =
             [
-                new MenuItemv2 ("Save", "", () => Save (_focusedTabView, e.Tab)),
-                new MenuItemv2 ("Close", "", () => Close (tv, e.Tab))
+                new MenuItem { Title = "Save", Action = () => Save (_focusedTabView!, e.Tab) },
+                new MenuItem { Title = "Close", Action = () => Close (tv, e.Tab) }
             ];
+        }
 
-            PopoverMenu? contextMenu = new (items);
-
-            // Registering with the PopoverManager will ensure that the context menu is closed when the view is no longer focused
-            // and the context menu is disposed when it is closed.
-            Application.Popover?.Register (contextMenu);
-            contextMenu?.MakeVisible (e.MouseEvent.ScreenPosition);
+        PopoverMenu contextMenu = new (items);
 
-            e.MouseEvent.Handled = true;
+        // Registering with the PopoverManager will ensure that the context menu is closed when the view is no longer focused
+        // and the context menu is disposed when it is closed.
+        if (sender is TabView tabView && tabView.App?.Popover is { })
+        {
+            tabView.App.Popover.Register (contextMenu);
         }
+
+        contextMenu.MakeVisible (e.MouseEvent.ScreenPosition);
+
+        e.MouseEvent.Handled = true;
     }
 
     private class OpenedFile (Notepad notepad) : Tab
     {
-        private Notepad _notepad = notepad;
+        private readonly Notepad _notepad = notepad;
 
         public OpenedFile CloneTo (TabView other)
         {
-            var newTab = new OpenedFile (_notepad) { DisplayText = base.Text, File = File };
+            OpenedFile newTab = new (_notepad) { DisplayText = Text, File = File };
             newTab.View = newTab.CreateTextView (newTab.File);
             newTab.SavedText = newTab.View.Text;
             newTab.RegisterTextViewEvents (other);
@@ -316,11 +357,11 @@ public class Notepad : Scenario
             return newTab;
         }
 
-        public View CreateTextView (FileInfo file)
+        public View CreateTextView (FileInfo? file)
         {
             var initialText = string.Empty;
 
-            if (file != null && file.Exists)
+            if (file is { Exists: true })
             {
                 initialText = System.IO.File.ReadAllText (file.FullName);
             }
@@ -336,11 +377,14 @@ public class Notepad : Scenario
             };
         }
 
-        public FileInfo File { get; set; }
+        public FileInfo? File { get; set; }
 
         public void RegisterTextViewEvents (TabView parent)
         {
-            var textView = (TextView)View;
+            if (View is not TextView textView)
+            {
+                return;
+            }
 
             // when user makes changes rename tab to indicate unsaved
             textView.ContentsChanged += (s, k) =>
@@ -362,25 +406,28 @@ public class Notepad : Scenario
                                                     DisplayText = Text.TrimEnd ('*');
                                                 }
                                             }
-                                            _notepad.LenShortcut.Title = $"Len:{textView.Text.Length}";
+
+                                            if (_notepad.LenShortcut is { })
+                                            {
+                                                _notepad.LenShortcut.Title = $"Len:{textView.Text.Length}";
+                                            }
                                         };
         }
 
         /// <summary>The text of the tab the last time it was saved</summary>
-        /// <value></value>
-        public string SavedText { get; set; }
+        public string? SavedText { get; set; }
 
-        public bool UnsavedChanges => !string.Equals (SavedText, View.Text);
+        public bool UnsavedChanges => View is { } && !string.Equals (SavedText, View.Text);
 
         internal void Save ()
         {
-            string newText = View.Text;
-
-            if (File is null || string.IsNullOrWhiteSpace (File.FullName))
+            if (View is null || File is null || string.IsNullOrWhiteSpace (File.FullName))
             {
                 return;
             }
 
+            string newText = View.Text;
+
             System.IO.File.WriteAllText (File.FullName, newText);
             SavedText = newText;
 

+ 2 - 2
Examples/UICatalog/Scenarios/NumericUpDownDemo.cs

@@ -266,14 +266,14 @@ internal class NumericUpDownEditor<T> : View where T : notnull
 
             void NumericUpDownOnIncrementChanged (object? o, EventArgs<T> eventArgs)
             {
-                _increment.Text = _numericUpDown.Increment.ToString ();
+                _increment.Text = _numericUpDown!.Increment?.ToString ();
             }
 
             Add (_numericUpDown);
 
             _value.Text = _numericUpDown.Text;
             _format.Text = _numericUpDown.Format;
-            _increment.Text = _numericUpDown.Increment.ToString ();
+            _increment.Text = _numericUpDown!.Increment?.ToString ();
         }
     }
 

+ 146 - 140
Examples/UICatalog/Scenarios/PosAlignDemo.cs

@@ -1,14 +1,10 @@
-using System;
-using System.Collections.Generic;
-using System.Linq;
-
 namespace UICatalog.Scenarios;
 
 [ScenarioMetadata ("Pos.Align", "Demonstrates Pos.Align")]
 [ScenarioCategory ("Layout")]
 public sealed class PosAlignDemo : Scenario
 {
-    private readonly Aligner _horizAligner = new () { AlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems};
+    private readonly Aligner _horizAligner = new () { AlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems };
     private int _leftMargin;
     private readonly Aligner _vertAligner = new () { AlignmentModes = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems };
     private int _topMargin;
@@ -24,7 +20,7 @@ public sealed class PosAlignDemo : Scenario
             Title = $"{Application.QuitKey} to Quit - Scenario: {GetName ()} - {GetDescription ()}"
         };
 
-        SetupControls (appWindow, Dimension.Width, Schemes.Toplevel);
+        SetupControls (appWindow, Dimension.Width, Schemes.Runnable);
 
         SetupControls (appWindow, Dimension.Height, Schemes.Error);
 
@@ -40,43 +36,42 @@ public sealed class PosAlignDemo : Scenario
 
     private void SetupControls (Window appWindow, Dimension dimension, Schemes scheme)
     {
-        RadioGroup alignRadioGroup = new ()
+        OptionSelector<Alignment> alignOptionSelector = new ()
         {
-            RadioLabels = Enum.GetNames<Alignment> (),
-            SchemeName = SchemeManager.SchemesToSchemeName (scheme),
+            SchemeName = SchemeManager.SchemesToSchemeName (scheme)
         };
 
         if (dimension == Dimension.Width)
         {
-            alignRadioGroup.X = Pos.Align (_horizAligner.Alignment);
-            alignRadioGroup.Y = Pos.Center ();
+            alignOptionSelector.X = Pos.Align (_horizAligner.Alignment);
+            alignOptionSelector.Y = Pos.Center ();
         }
         else
         {
-            alignRadioGroup.X = Pos.Center ();
-            alignRadioGroup.Y = Pos.Align (_vertAligner.Alignment);
+            alignOptionSelector.X = Pos.Center ();
+            alignOptionSelector.Y = Pos.Align (_vertAligner.Alignment);
         }
 
-        alignRadioGroup.SelectedItemChanged += (s, e) =>
-                                               {
-                                                   if (dimension == Dimension.Width)
-                                                   {
-                                                       _horizAligner.Alignment =
-                                                           (Alignment)Enum.Parse (
-                                                                                  typeof (Alignment),
-                                                                                  alignRadioGroup.RadioLabels [alignRadioGroup.SelectedItem]);
-                                                       UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
-                                                   }
-                                                   else
-                                                   {
-                                                       _vertAligner.Alignment =
-                                                           (Alignment)Enum.Parse (
-                                                                                  typeof (Alignment),
-                                                                                  alignRadioGroup.RadioLabels [alignRadioGroup.SelectedItem]);
-                                                       UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
-                                                   }
-                                               };
-        appWindow.Add (alignRadioGroup);
+        alignOptionSelector.ValueChanged += (s, e) =>
+                                            {
+                                                if (alignOptionSelector.Value is null)
+                                                {
+                                                    return;
+                                                }
+
+                                                if (dimension == Dimension.Width)
+                                                {
+                                                    _horizAligner.Alignment = alignOptionSelector.Value.Value;
+
+                                                    UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
+                                                }
+                                                else
+                                                {
+                                                    _vertAligner.Alignment = alignOptionSelector.Value.Value;
+                                                    UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
+                                                }
+                                            };
+        appWindow.Add (alignOptionSelector);
 
         CheckBox endToStartCheckBox = new ()
         {
@@ -88,32 +83,32 @@ public sealed class PosAlignDemo : Scenario
         {
             endToStartCheckBox.CheckedState = _horizAligner.AlignmentModes.HasFlag (AlignmentModes.EndToStart) ? CheckState.Checked : CheckState.UnChecked;
             endToStartCheckBox.X = Pos.Align (_horizAligner.Alignment);
-            endToStartCheckBox.Y = Pos.Top (alignRadioGroup);
+            endToStartCheckBox.Y = Pos.Top (alignOptionSelector);
         }
         else
         {
             endToStartCheckBox.CheckedState = _vertAligner.AlignmentModes.HasFlag (AlignmentModes.EndToStart) ? CheckState.Checked : CheckState.UnChecked;
-            endToStartCheckBox.X = Pos.Left (alignRadioGroup);
+            endToStartCheckBox.X = Pos.Left (alignOptionSelector);
             endToStartCheckBox.Y = Pos.Align (_vertAligner.Alignment);
         }
 
         endToStartCheckBox.CheckedStateChanging += (s, e) =>
-                                      {
-                                          if (dimension == Dimension.Width)
-                                          {
-                                              _horizAligner.AlignmentModes = e.Result == CheckState.Checked
-                                                                                 ? _horizAligner.AlignmentModes | AlignmentModes.EndToStart
-                                                                                 : _horizAligner.AlignmentModes & ~AlignmentModes.EndToStart;
-                                              UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
-                                          }
-                                          else
-                                          {
-                                              _vertAligner.AlignmentModes = e.Result == CheckState.Checked
-                                                                                ? _vertAligner.AlignmentModes | AlignmentModes.EndToStart
-                                                                                : _vertAligner.AlignmentModes & ~AlignmentModes.EndToStart;
-                                              UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
-                                          }
-                                      };
+                                                   {
+                                                       if (dimension == Dimension.Width)
+                                                       {
+                                                           _horizAligner.AlignmentModes = e.Result == CheckState.Checked
+                                                                                              ? _horizAligner.AlignmentModes | AlignmentModes.EndToStart
+                                                                                              : _horizAligner.AlignmentModes & ~AlignmentModes.EndToStart;
+                                                           UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
+                                                       }
+                                                       else
+                                                       {
+                                                           _vertAligner.AlignmentModes = e.Result == CheckState.Checked
+                                                                                             ? _vertAligner.AlignmentModes | AlignmentModes.EndToStart
+                                                                                             : _vertAligner.AlignmentModes & ~AlignmentModes.EndToStart;
+                                                           UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
+                                                       }
+                                                   };
         appWindow.Add (endToStartCheckBox);
 
         CheckBox ignoreFirstOrLast = new ()
@@ -124,34 +119,35 @@ public sealed class PosAlignDemo : Scenario
 
         if (dimension == Dimension.Width)
         {
-            ignoreFirstOrLast.CheckedState = _horizAligner.AlignmentModes.HasFlag (AlignmentModes.IgnoreFirstOrLast) ? CheckState.Checked : CheckState.UnChecked;
+            ignoreFirstOrLast.CheckedState =
+                _horizAligner.AlignmentModes.HasFlag (AlignmentModes.IgnoreFirstOrLast) ? CheckState.Checked : CheckState.UnChecked;
             ignoreFirstOrLast.X = Pos.Align (_horizAligner.Alignment);
-            ignoreFirstOrLast.Y = Pos.Top (alignRadioGroup);
+            ignoreFirstOrLast.Y = Pos.Top (alignOptionSelector);
         }
         else
         {
             ignoreFirstOrLast.CheckedState = _vertAligner.AlignmentModes.HasFlag (AlignmentModes.IgnoreFirstOrLast) ? CheckState.Checked : CheckState.UnChecked;
-            ignoreFirstOrLast.X = Pos.Left (alignRadioGroup);
+            ignoreFirstOrLast.X = Pos.Left (alignOptionSelector);
             ignoreFirstOrLast.Y = Pos.Align (_vertAligner.Alignment);
         }
 
         ignoreFirstOrLast.CheckedStateChanging += (s, e) =>
-                                     {
-                                         if (dimension == Dimension.Width)
-                                         {
-                                             _horizAligner.AlignmentModes = e.Result == CheckState.Checked
-                                                     ? _horizAligner.AlignmentModes | AlignmentModes.IgnoreFirstOrLast
-                                                     : _horizAligner.AlignmentModes & ~AlignmentModes.IgnoreFirstOrLast;
-                                             UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
-                                         }
-                                         else
-                                         {
-                                             _vertAligner.AlignmentModes = e.Result == CheckState.Checked
-                                                                               ? _vertAligner.AlignmentModes | AlignmentModes.IgnoreFirstOrLast
-                                                                               : _vertAligner.AlignmentModes & ~AlignmentModes.IgnoreFirstOrLast;
-                                             UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
-                                         }
-                                     };
+                                                  {
+                                                      if (dimension == Dimension.Width)
+                                                      {
+                                                          _horizAligner.AlignmentModes = e.Result == CheckState.Checked
+                                                                                             ? _horizAligner.AlignmentModes | AlignmentModes.IgnoreFirstOrLast
+                                                                                             : _horizAligner.AlignmentModes & ~AlignmentModes.IgnoreFirstOrLast;
+                                                          UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
+                                                      }
+                                                      else
+                                                      {
+                                                          _vertAligner.AlignmentModes = e.Result == CheckState.Checked
+                                                                                            ? _vertAligner.AlignmentModes | AlignmentModes.IgnoreFirstOrLast
+                                                                                            : _vertAligner.AlignmentModes & ~AlignmentModes.IgnoreFirstOrLast;
+                                                          UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
+                                                      }
+                                                  };
         appWindow.Add (ignoreFirstOrLast);
 
         CheckBox addSpacesBetweenItems = new ()
@@ -162,34 +158,40 @@ public sealed class PosAlignDemo : Scenario
 
         if (dimension == Dimension.Width)
         {
-            addSpacesBetweenItems.CheckedState = _horizAligner.AlignmentModes.HasFlag (AlignmentModes.AddSpaceBetweenItems) ? CheckState.Checked : CheckState.UnChecked;
+            addSpacesBetweenItems.CheckedState =
+                _horizAligner.AlignmentModes.HasFlag (AlignmentModes.AddSpaceBetweenItems) ? CheckState.Checked : CheckState.UnChecked;
             addSpacesBetweenItems.X = Pos.Align (_horizAligner.Alignment);
-            addSpacesBetweenItems.Y = Pos.Top (alignRadioGroup);
+            addSpacesBetweenItems.Y = Pos.Top (alignOptionSelector);
         }
         else
         {
-            addSpacesBetweenItems.CheckedState = _vertAligner.AlignmentModes.HasFlag (AlignmentModes.AddSpaceBetweenItems) ? CheckState.Checked : CheckState.UnChecked;
-            addSpacesBetweenItems.X = Pos.Left (alignRadioGroup);
+            addSpacesBetweenItems.CheckedState =
+                _vertAligner.AlignmentModes.HasFlag (AlignmentModes.AddSpaceBetweenItems) ? CheckState.Checked : CheckState.UnChecked;
+            addSpacesBetweenItems.X = Pos.Left (alignOptionSelector);
             addSpacesBetweenItems.Y = Pos.Align (_vertAligner.Alignment);
         }
 
         addSpacesBetweenItems.CheckedStateChanging += (s, e) =>
-                                         {
-                                             if (dimension == Dimension.Width)
-                                             {
-                                                 _horizAligner.AlignmentModes = e.Result == CheckState.Checked
-                                                                                    ? _horizAligner.AlignmentModes | AlignmentModes.AddSpaceBetweenItems
-                                                                                    : _horizAligner.AlignmentModes & ~AlignmentModes.AddSpaceBetweenItems;
-                                                 UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
-                                             }
-                                             else
-                                             {
-                                                 _vertAligner.AlignmentModes = e.Result == CheckState.Checked
-                                                                                   ? _vertAligner.AlignmentModes | AlignmentModes.AddSpaceBetweenItems
-                                                                                   : _vertAligner.AlignmentModes & ~AlignmentModes.AddSpaceBetweenItems;
-                                                 UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
-                                             }
-                                         };
+                                                      {
+                                                          if (dimension == Dimension.Width)
+                                                          {
+                                                              _horizAligner.AlignmentModes = e.Result == CheckState.Checked
+                                                                                                 ? _horizAligner.AlignmentModes
+                                                                                                   | AlignmentModes.AddSpaceBetweenItems
+                                                                                                 : _horizAligner.AlignmentModes
+                                                                                                   & ~AlignmentModes.AddSpaceBetweenItems;
+                                                              UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
+                                                          }
+                                                          else
+                                                          {
+                                                              _vertAligner.AlignmentModes = e.Result == CheckState.Checked
+                                                                                                ? _vertAligner.AlignmentModes
+                                                                                                  | AlignmentModes.AddSpaceBetweenItems
+                                                                                                : _vertAligner.AlignmentModes
+                                                                                                  & ~AlignmentModes.AddSpaceBetweenItems;
+                                                              UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
+                                                          }
+                                                      };
 
         appWindow.Add (addSpacesBetweenItems);
 
@@ -202,7 +204,7 @@ public sealed class PosAlignDemo : Scenario
         if (dimension == Dimension.Width)
         {
             margin.X = Pos.Align (_horizAligner.Alignment);
-            margin.Y = Pos.Top (alignRadioGroup);
+            margin.Y = Pos.Top (alignOptionSelector);
         }
         else
         {
@@ -211,31 +213,31 @@ public sealed class PosAlignDemo : Scenario
         }
 
         margin.CheckedStateChanging += (s, e) =>
-                          {
-                              if (dimension == Dimension.Width)
-                              {
-                                  _leftMargin = e.Result == CheckState.Checked ? 1 : 0;
-                                  UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
-                              }
-                              else
-                              {
-                                  _topMargin = e.Result == CheckState.Checked ? 1 : 0;
-                                  UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
-                              }
-                          };
+                                       {
+                                           if (dimension == Dimension.Width)
+                                           {
+                                               _leftMargin = e.Result == CheckState.Checked ? 1 : 0;
+                                               UpdatePosAlignObjects (appWindow, dimension, _horizAligner);
+                                           }
+                                           else
+                                           {
+                                               _topMargin = e.Result == CheckState.Checked ? 1 : 0;
+                                               UpdatePosAlignObjects (appWindow, dimension, _vertAligner);
+                                           }
+                                       };
         appWindow.Add (margin);
 
         List<Button> addedViews =
         [
             new ()
             {
-                X = dimension == Dimension.Width ? Pos.Align (_horizAligner.Alignment) : Pos.Left (alignRadioGroup),
-                Y = dimension == Dimension.Width ? Pos.Top (alignRadioGroup) : Pos.Align (_vertAligner.Alignment),
+                X = dimension == Dimension.Width ? Pos.Align (_horizAligner.Alignment) : Pos.Left (alignOptionSelector),
+                Y = dimension == Dimension.Width ? Pos.Top (alignOptionSelector) : Pos.Align (_vertAligner.Alignment),
                 Text = NumberToWords.Convert (0)
             }
         ];
 
-        NumericUpDown<int> addedViewsUpDown = new()
+        NumericUpDown<int> addedViewsUpDown = new ()
         {
             Width = 9,
             Title = "Added",
@@ -247,14 +249,14 @@ public sealed class PosAlignDemo : Scenario
         if (dimension == Dimension.Width)
         {
             addedViewsUpDown.X = Pos.Align (_horizAligner.Alignment);
-            addedViewsUpDown.Y = Pos.Top (alignRadioGroup);
-            addedViewsUpDown.Border.Thickness = new (0, 1, 0, 0);
+            addedViewsUpDown.Y = Pos.Top (alignOptionSelector);
+            addedViewsUpDown.Border!.Thickness = new (0, 1, 0, 0);
         }
         else
         {
-            addedViewsUpDown.X = Pos.Left (alignRadioGroup);
+            addedViewsUpDown.X = Pos.Left (alignOptionSelector);
             addedViewsUpDown.Y = Pos.Align (_vertAligner.Alignment);
-            addedViewsUpDown.Border.Thickness = new (1, 0, 0, 0);
+            addedViewsUpDown.Border!.Thickness = new (1, 0, 0, 0);
         }
 
         addedViewsUpDown.ValueChanging += (s, e) =>
@@ -286,8 +288,10 @@ public sealed class PosAlignDemo : Scenario
                                                   {
                                                       var button = new Button
                                                       {
-                                                          X = dimension == Dimension.Width ? Pos.Align (_horizAligner.Alignment) : Pos.Left (alignRadioGroup),
-                                                          Y = dimension == Dimension.Width ? Pos.Top (alignRadioGroup) : Pos.Align (_vertAligner.Alignment),
+                                                          X = dimension == Dimension.Width
+                                                                  ? Pos.Align (_horizAligner.Alignment)
+                                                                  : Pos.Left (alignOptionSelector),
+                                                          Y = dimension == Dimension.Width ? Pos.Top (alignOptionSelector) : Pos.Align (_vertAligner.Alignment),
                                                           Text = NumberToWords.Convert (i + 1)
                                                       };
                                                       appWindow.Add (button);
@@ -319,7 +323,7 @@ public sealed class PosAlignDemo : Scenario
                                         aligner.Alignment,
                                         aligner.AlignmentModes,
                                         posAlign!.GroupId);
-                    view.Margin.Thickness = new (_leftMargin, view.Margin.Thickness.Top, view.Margin.Thickness.Right, view.Margin.Thickness.Bottom);
+                    view.Margin!.Thickness = new (_leftMargin, view.Margin!.Thickness.Top, view.Margin!.Thickness.Right, view.Margin!.Thickness.Bottom);
                 }
                 else
                 {
@@ -330,7 +334,7 @@ public sealed class PosAlignDemo : Scenario
                                         aligner.AlignmentModes,
                                         posAlign!.GroupId);
 
-                    view.Margin.Thickness = new (view.Margin.Thickness.Left, _topMargin, view.Margin.Thickness.Right, view.Margin.Thickness.Bottom);
+                    view.Margin!.Thickness = new (view.Margin!.Thickness.Left, _topMargin, view.Margin!.Thickness.Right, view.Margin!.Thickness.Bottom);
                 }
             }
         }
@@ -351,46 +355,48 @@ public sealed class PosAlignDemo : Scenario
             Width = Dim.Percent (40),
             Height = Dim.Percent (40)
         };
-        container.Padding.Thickness = new (8, 1, 0, 0);
+        container.Padding!.Thickness = new (8, 1, 0, 0);
         container.Padding.SchemeName = "Error";
 
         Aligner widthAligner = new () { AlignmentModes = AlignmentModes.StartToEnd };
 
-        RadioGroup widthAlignRadioGroup = new ()
+        OptionSelector widthAlignOptionSelector = new ()
         {
-            RadioLabels = Enum.GetNames<Alignment> (),
+            Labels = Enum.GetNames<Alignment> (),
             Orientation = Orientation.Horizontal,
             X = Pos.Center ()
         };
-        container.Padding.Add (widthAlignRadioGroup);
-
-        widthAlignRadioGroup.SelectedItemChanged += (sender, e) =>
-                                                    {
-                                                        widthAligner.Alignment =
-                                                            (Alignment)Enum.Parse (
-                                                                                   typeof (Alignment),
-                                                                                   widthAlignRadioGroup.RadioLabels [widthAlignRadioGroup.SelectedItem]);
-                                                        UpdatePosAlignObjects (container, Dimension.Width, widthAligner);
-                                                    };
+        container.Padding.Add (widthAlignOptionSelector);
+
+        widthAlignOptionSelector.ValueChanged += (_, _) =>
+                                                        {
+                                                            widthAligner.Alignment =
+                                                                (Alignment)Enum.Parse (
+                                                                                       typeof (Alignment),
+                                                                                       widthAlignOptionSelector.Labels [widthAlignOptionSelector
+                                                                                           .Value!.Value]);
+                                                            UpdatePosAlignObjects (container, Dimension.Width, widthAligner);
+                                                        };
 
         Aligner heightAligner = new () { AlignmentModes = AlignmentModes.StartToEnd };
 
-        RadioGroup heightAlignRadioGroup = new ()
+        OptionSelector heightAlignOptionSelector = new ()
         {
-            RadioLabels = Enum.GetNames<Alignment> (),
+            Labels = Enum.GetNames<Alignment> (),
             Orientation = Orientation.Vertical,
             Y = Pos.Center ()
         };
-        container.Padding.Add (heightAlignRadioGroup);
-
-        heightAlignRadioGroup.SelectedItemChanged += (sender, e) =>
-                                                     {
-                                                         heightAligner.Alignment =
-                                                             (Alignment)Enum.Parse (
-                                                                                    typeof (Alignment),
-                                                                                    heightAlignRadioGroup.RadioLabels [heightAlignRadioGroup.SelectedItem]);
-                                                         UpdatePosAlignObjects (container, Dimension.Height, heightAligner);
-                                                     };
+        container.Padding.Add (heightAlignOptionSelector);
+
+        heightAlignOptionSelector.ValueChanged += (sender, e) =>
+                                                         {
+                                                             heightAligner.Alignment =
+                                                                 (Alignment)Enum.Parse (
+                                                                                        typeof (Alignment),
+                                                                                        heightAlignOptionSelector.Labels [heightAlignOptionSelector
+                                                                                            .Value!.Value]);
+                                                             UpdatePosAlignObjects (container, Dimension.Height, heightAligner);
+                                                         };
 
         for (var i = 0; i < 9; i++)
 
@@ -401,7 +407,7 @@ public sealed class PosAlignDemo : Scenario
                 Text = $"{i}",
                 BorderStyle = LineStyle.Dashed,
                 Height = Dim.Auto (),
-                Width = Dim.Auto() + 2
+                Width = Dim.Auto () + 2
             };
 
             v.X = Pos.Align (widthAligner.Alignment, widthAligner.AlignmentModes, i / 3);

+ 1 - 1
Examples/UICatalog/Scenarios/Progress.cs

@@ -43,7 +43,7 @@ public class Progress : Scenario
                                                                       {
                                                                           // Note the check for Mainloop being valid. System.Timers can run after they are Disposed.
                                                                           // This code must be defensive for that. 
-                                                                          Application.Invoke (() => systemTimerDemo.Pulse ());
+                                                                          Application.Invoke ((_) => systemTimerDemo.Pulse ());
                                                                       },
                                                                       null,
                                                                       0,

+ 31 - 21
Examples/UICatalog/Scenarios/ProgressBarStyles.cs

@@ -27,7 +27,7 @@ public class ProgressBarStyles : Scenario
     {
         Application.Init ();
 
-        Window app = new ()
+        Window win = new ()
         {
             Title = GetQuitKeyAndName (), BorderStyle = LineStyle.Single,
         };
@@ -38,7 +38,7 @@ public class ProgressBarStyles : Scenario
             ShowViewIdentifier = true
 
         };
-        app.Add (editor);
+        win.Add (editor);
 
         View container = new ()
         {
@@ -47,7 +47,7 @@ public class ProgressBarStyles : Scenario
             Width = Dim.Fill (),
             Height = Dim.Fill (),
         };
-        app.Add (container);
+        win.Add (container);
 
         const float fractionStep = 0.01F;
 
@@ -132,15 +132,15 @@ public class ProgressBarStyles : Scenario
         List<ProgressBarFormat> pbFormatEnum =
             Enum.GetValues (typeof (ProgressBarFormat)).Cast<ProgressBarFormat> ().ToList ();
 
-        var rbPBFormat = new RadioGroup
+        OptionSelector<ProgressBarFormat> osPbFormat = new ()
         {
             BorderStyle = LineStyle.Single,
             Title = "ProgressBarFormat",
             X = Pos.Center (),
             Y = Pos.Align (Alignment.Start),
-            RadioLabels = pbFormatEnum.Select (e => e.ToString ()).ToArray ()
+            AssignHotKeys = true
         };
-        container.Add (rbPBFormat);
+        container.Add (osPbFormat);
 
         var button = new Button
         {
@@ -161,7 +161,7 @@ public class ProgressBarStyles : Scenario
         };
         container.Add (blocksPB);
 
-        rbPBFormat.SelectedItem = (int)blocksPB.ProgressBarFormat;
+        osPbFormat.Value = blocksPB.ProgressBarFormat;
 
         var continuousPB = new ProgressBar
         {
@@ -256,13 +256,19 @@ public class ProgressBarStyles : Scenario
                                       };
 
 
-        rbPBFormat.SelectedItemChanged += (s, e) =>
-                                          {
-                                              blocksPB.ProgressBarFormat = (ProgressBarFormat)e.SelectedItem;
-                                              continuousPB.ProgressBarFormat = (ProgressBarFormat)e.SelectedItem;
-                                              marqueesBlocksPB.ProgressBarFormat = (ProgressBarFormat)e.SelectedItem;
-                                              marqueesContinuousPB.ProgressBarFormat = (ProgressBarFormat)e.SelectedItem;
-                                          };
+        osPbFormat.ValueChanged += (s, e) =>
+                                   {
+                                       if (e.Value is null)
+                                       {
+                                           return;
+                                       }
+
+                                       blocksPB.ProgressBarFormat = e.Value.Value;
+                                       continuousPB.ProgressBarFormat = e.Value.Value;
+                                       marqueesBlocksPB.ProgressBarFormat = e.Value.Value;
+                                       marqueesContinuousPB.ProgressBarFormat = e.Value.Value;
+
+                                   };
 
         ckbBidirectional.CheckedStateChanging += (s, e) =>
                                    {
@@ -272,8 +278,8 @@ public class ProgressBarStyles : Scenario
 
 
 
-        app.Initialized += App_Initialized;
-        app.Unloaded += App_Unloaded;
+        win.Initialized += Win_Initialized;
+        win.IsRunningChanged += Win_IsRunningChanged;
 
         _pulseTimer = new Timer (
                                  _ =>
@@ -286,14 +292,18 @@ public class ProgressBarStyles : Scenario
                                  0,
                                  300
                                 );
-        Application.Run (app);
-        app.Dispose ();
+        Application.Run (win);
+        win.Dispose ();
         Application.Shutdown ();
 
         return;
 
-        void App_Unloaded (object sender, EventArgs args)
+        void Win_IsRunningChanged (object sender, EventArgs<bool> args)
         {
+            if (args.Value)
+            {
+                return;
+            }
             if (_fractionTimer != null)
             {
                 _fractionTimer.Dispose ();
@@ -306,11 +316,11 @@ public class ProgressBarStyles : Scenario
                 _pulseTimer = null;
             }
 
-            app.Unloaded -= App_Unloaded;
+            win.IsRunningChanged -= Win_IsRunningChanged;
         }
     }
 
-    private void App_Initialized (object sender, EventArgs e)
+    private void Win_Initialized (object sender, EventArgs e)
     {
         _pbList.SelectedItem = 0;
     }

+ 37 - 64
Examples/UICatalog/Scenarios/RegionScenario.cs

@@ -1,7 +1,4 @@
 #nullable enable
-using System;
-using System.Collections.Generic;
-using System.Linq;
 using System.Text;
 using UICatalog;
 using UICatalog.Scenarios;
@@ -27,31 +24,31 @@ public class RegionScenario : Scenario
     {
         Application.Init ();
 
-        Window app = new ()
+        Window appWindow = new ()
         {
             Title = GetQuitKeyAndName (),
             TabStop = TabBehavior.TabGroup
         };
-        app.Padding!.Thickness = new (1);
+        appWindow.Padding!.Thickness = new (1);
 
         var tools = new ToolsView { Title = "Tools", X = Pos.AnchorEnd (), Y = 2 };
 
-        tools.CurrentAttribute = app.GetAttributeForRole (VisualRole.HotNormal);
+        tools.CurrentAttribute = appWindow.GetAttributeForRole (VisualRole.HotNormal);
 
         tools.SetStyle += b =>
                           {
-                              _drawStyle = (RegionDrawStyles)b;
-                              app.SetNeedsDraw ();
+                              _drawStyle = b;
+                              appWindow.SetNeedsDraw ();
                           };
 
         tools.RegionOpChanged += (s, e) => { _regionOp = e; };
 
         //tools.AddLayer += () => canvas.AddLayer ();
 
-        app.Add (tools);
+        appWindow.Add (tools);
 
         // Add drag handling to window
-        app.MouseEvent += (s, e) =>
+        appWindow.MouseEvent += (s, e) =>
                           {
                               if (e.Flags.HasFlag (MouseFlags.Button1Pressed))
                               {
@@ -65,7 +62,7 @@ public class RegionScenario : Scenario
                                       // Drag
                                       if (_isDragging && _dragStart.HasValue)
                                       {
-                                          app.SetNeedsDraw ();
+                                          appWindow.SetNeedsDraw ();
                                       }
                                   }
                               }
@@ -80,31 +77,31 @@ public class RegionScenario : Scenario
                                       _dragStart = null;
                                   }
 
-                                  app.SetNeedsDraw ();
+                                  appWindow.SetNeedsDraw ();
                               }
                           };
 
         // Draw the regions
-        app.DrawingContent += (s, e) =>
+        appWindow.DrawingContent += (s, e) =>
                               {
                                   // Draw all regions with single line style
                                   //_region.FillRectangles (_attribute.Value, _fillRune);
                                   switch (_drawStyle)
                                   {
                                       case RegionDrawStyles.FillOnly:
-                                          _region.FillRectangles (tools.CurrentAttribute!.Value, _previewFillRune);
+                                          _region.FillRectangles (appWindow.App?.Driver, tools.CurrentAttribute!.Value, _previewFillRune);
 
                                           break;
 
                                       case RegionDrawStyles.InnerBoundaries:
-                                          _region.DrawBoundaries (app.LineCanvas, LineStyle.Single, tools.CurrentAttribute);
-                                          _region.FillRectangles (tools.CurrentAttribute!.Value, (Rune)' ');
+                                          _region.DrawBoundaries (appWindow.LineCanvas, LineStyle.Single, tools.CurrentAttribute);
+                                          _region.FillRectangles (appWindow.App?.Driver, tools.CurrentAttribute!.Value, (Rune)' ');
 
                                           break;
 
                                       case RegionDrawStyles.OuterBoundary:
-                                          _region.DrawOuterBoundary (app.LineCanvas, LineStyle.Single, tools.CurrentAttribute);
-                                          _region.FillRectangles (tools.CurrentAttribute!.Value, (Rune)' ');
+                                          _region.DrawOuterBoundary (appWindow.LineCanvas, LineStyle.Single, tools.CurrentAttribute);
+                                          _region.FillRectangles (appWindow.App?.Driver, tools.CurrentAttribute!.Value, (Rune)' ');
 
                                           break;
                                   }
@@ -112,14 +109,14 @@ public class RegionScenario : Scenario
                                   // If currently dragging, draw preview rectangle
                                   if (_isDragging && _dragStart.HasValue)
                                   {
-                                      Point currentMousePos = Application.GetLastMousePosition ()!.Value;
+                                      Point currentMousePos = appWindow.App!.Mouse.LastMousePosition!.Value;
                                       Rectangle previewRect = GetRectFromPoints (_dragStart.Value, currentMousePos);
                                       var previewRegion = new Region (previewRect);
 
-                                      previewRegion.FillRectangles (tools.CurrentAttribute!.Value, (Rune)' ');
+                                      previewRegion.FillRectangles (appWindow.App.Driver, tools.CurrentAttribute!.Value, (Rune)' ');
 
                                       previewRegion.DrawBoundaries (
-                                                                    app.LineCanvas,
+                                                                    appWindow.LineCanvas,
                                                                     LineStyle.Dashed,
                                                                     new (
                                                                          tools.CurrentAttribute!.Value.Foreground.GetBrighterColor (),
@@ -127,10 +124,10 @@ public class RegionScenario : Scenario
                                   }
                               };
 
-        Application.Run (app);
+        Application.Run (appWindow);
 
         // Clean up
-        app.Dispose ();
+        appWindow.Dispose ();
         Application.Shutdown ();
     }
 
@@ -169,8 +166,8 @@ public class ToolsView : Window
 {
     //private Button _addLayerBtn;
     private readonly AttributeView _attributeView = new ();
-    private RadioGroup? _stylePicker;
-    private RegionOpSelector? _regionOpSelector;
+    private OptionSelector<RegionDrawStyles>? _stylePicker;
+    private OptionSelector<RegionOp>? _regionOpSelector;
 
     public Attribute? CurrentAttribute
     {
@@ -197,22 +194,30 @@ public class ToolsView : Window
         _stylePicker = new ()
         {
             Width = Dim.Fill (),
-            X = 0, Y = Pos.Bottom (_attributeView) + 1, RadioLabels = Enum.GetNames<RegionDrawStyles> ().Select (n => n = "_" + n).ToArray ()
+            X = 0, Y = Pos.Bottom (_attributeView) + 1,
+            AssignHotKeys = true
         };
         _stylePicker.BorderStyle = LineStyle.Single;
         _stylePicker.Border!.Thickness = new (0, 1, 0, 0);
         _stylePicker.Title = "Draw Style";
 
-        _stylePicker.SelectedItemChanged += (s, a) => { SetStyle?.Invoke ((LineStyle)a.SelectedItem!); };
-        _stylePicker.SelectedItem = (int)RegionDrawStyles.FillOnly;
+        _stylePicker.ValueChanged += (s, a) => { SetStyle?.Invoke ((RegionDrawStyles)a.Value!); };
+        _stylePicker.Value = RegionDrawStyles.FillOnly;
 
         _regionOpSelector = new ()
         {
             X = 0,
-            Y = Pos.Bottom (_stylePicker) + 1
+            Y = Pos.Bottom (_stylePicker) + 1,
+            AssignHotKeys = true
         };
-        _regionOpSelector.SelectedItemChanged += (s, a) => { RegionOpChanged?.Invoke (this, a); };
-        _regionOpSelector.SelectedItem = RegionOp.MinimalUnion;
+        _regionOpSelector.ValueChanged += (s, a) =>
+                                          {
+                                              if (a.Value is { })
+                                              {
+                                                  RegionOpChanged?.Invoke (this, (RegionOp)a.Value);
+                                              }
+                                          };
+        _regionOpSelector.Value = RegionOp.MinimalUnion;
 
         //_addLayerBtn = new () { Text = "New Layer", X = Pos.Center (), Y = Pos.Bottom (_stylePicker) };
 
@@ -222,39 +227,7 @@ public class ToolsView : Window
 
     public event EventHandler<Attribute?>? AttributeChanged;
     public event EventHandler<RegionOp>? RegionOpChanged;
-    public event Action<LineStyle>? SetStyle;
-}
-
-public class RegionOpSelector : View
-{
-    private readonly RadioGroup _radioGroup;
-
-    public RegionOpSelector ()
-    {
-        Width = Dim.Auto ();
-        Height = Dim.Auto ();
-
-        BorderStyle = LineStyle.Single;
-        Border!.Thickness = new (0, 1, 0, 0);
-        Title = "RegionOp";
-
-        _radioGroup = new ()
-        {
-            X = 0,
-            Y = 0,
-            RadioLabels = Enum.GetNames<RegionOp> ().Select (n => n = "_" + n).ToArray ()
-        };
-        _radioGroup.SelectedItemChanged += (s, a) => { SelectedItemChanged?.Invoke (this, (RegionOp)a.SelectedItem!); };
-        Add (_radioGroup);
-    }
-
-    public event EventHandler<RegionOp>? SelectedItemChanged;
-
-    public RegionOp SelectedItem
-    {
-        get => (RegionOp)_radioGroup.SelectedItem;
-        set => _radioGroup.SelectedItem = (int)value;
-    }
+    public event Action<RegionDrawStyles>? SetStyle;
 }
 
 public class AttributeView : View

+ 4 - 4
Examples/UICatalog/Scenarios/RunTExample.cs

@@ -8,7 +8,7 @@ public class RunTExample : Scenario
     public override void Main ()
     {
         // No need to call Init if Application.Run<T> is used
-        Application.Run<ExampleWindow> ().Dispose ();
+        Application.Run<ExampleWindow> ();
         Application.Shutdown ();
     }
 
@@ -63,12 +63,12 @@ public class RunTExample : Scenario
                                {
                                    if (_usernameText.Text == "admin" && passwordText.Text == "password")
                                    {
-                                       MessageBox.Query ("Login Successful", $"Username: {_usernameText.Text}", "Ok");
-                                       Application.RequestStop ();
+                                       MessageBox.Query (App, "Login Successful", $"Username: {_usernameText.Text}", "Ok");
+                                       App?.RequestStop ();
                                    }
                                    else
                                    {
-                                       MessageBox.ErrorQuery (
+                                       MessageBox.ErrorQuery (App,
                                                               "Error Logging In",
                                                               "Incorrect username or password (hint: admin/password)",
                                                               "Ok"

+ 177 - 74
Examples/UICatalog/Scenarios/RuneWidthGreaterThanOne.cs

@@ -1,4 +1,6 @@
-using System;
+#nullable enable
+
+using System;
 
 namespace UICatalog.Scenarios;
 
@@ -8,99 +10,173 @@ namespace UICatalog.Scenarios;
 [ScenarioCategory ("Tests")]
 public class RuneWidthGreaterThanOne : Scenario
 {
-    private Button _button;
-    private Label _label;
-    private Label _labelR;
-    private Label _labelV;
-    private string _lastRunesUsed;
-    private TextField _text;
-    private Window _win;
+    private Button? _button;
+    private Label? _label;
+    private Label? _labelR;
+    private Label? _labelV;
+    private string? _lastRunesUsed;
+    private TextField? _text;
+    private Window? _win;
 
     public override void Main ()
     {
         Application.Init ();
 
-        Toplevel topLevel = new ();
+        // Window (top-level)
+        Window win = new ()
+        {
+            X = 5,
+            Y = 5,
+            Width = Dim.Fill (22),
+            Height = Dim.Fill (5),
+            Arrangement = ViewArrangement.Overlapped | ViewArrangement.Movable
+        };
+        _win = win;
+
+        // MenuBar
+        MenuBar menu = new ();
+
+        // Controls
+        _label = new ()
+        {
+            X = Pos.Center (),
+            Y = 1
+        };
+
+        _text = new ()
+        {
+            X = Pos.Center (),
+            Y = 3,
+            Width = 20
+        };
 
-        var menu = new MenuBar
+        _button = new ()
         {
-            Menus =
-            [
-                new MenuBarItem (
-                                 "Padding",
-                                 new MenuItem []
-                                 {
-                                     new (
-                                          "With Padding",
-                                          "",
-                                          () => _win.Padding.Thickness =
-                                                    new Thickness (1)
-                                         ),
-                                     new (
-                                          "Without Padding",
-                                          "",
-                                          () => _win.Padding.Thickness =
-                                                    new Thickness (0)
-                                         )
-                                 }
-                                ),
-                new MenuBarItem (
-                                 "BorderStyle",
-                                 new MenuItem []
-                                 {
-                                     new (
-                                          "Single",
-                                          "",
-                                          () => _win.BorderStyle = LineStyle.Single
-                                         ),
-                                     new (
-                                          "None",
-                                          "",
-                                          () => _win.BorderStyle = LineStyle.None
-                                         )
-                                 }
-                                ),
-                new MenuBarItem (
-                                 "Runes length",
-                                 new MenuItem []
-                                 {
-                                     new ("Wide", "", WideRunes),
-                                     new ("Narrow", "", NarrowRunes),
-                                     new ("Mixed", "", MixedRunes)
-                                 }
-                                )
-            ]
+            X = Pos.Center (),
+            Y = 5
         };
 
-        _label = new Label
+        _labelR = new ()
         {
-            X = Pos.Center (), Y = 1,
+            X = Pos.AnchorEnd (30),
+            Y = 18
         };
-        _text = new TextField { X = Pos.Center (), Y = 3, Width = 20 };
-        _button = new Button { X = Pos.Center (), Y = 5 };
-        _labelR = new Label { X = Pos.AnchorEnd (30), Y = 18 };
 
-        _labelV = new Label
+        _labelV = new ()
         {
-            TextDirection = TextDirection.TopBottom_LeftRight, X = Pos.AnchorEnd (30), Y = Pos.Bottom (_labelR)
+            TextDirection = TextDirection.TopBottom_LeftRight,
+            X = Pos.AnchorEnd (30),
+            Y = Pos.Bottom (_labelR)
         };
-        _win = new Window { X = 5, Y = 5, Width = Dim.Fill (22), Height = Dim.Fill (5) };
-        _win.Add (_label, _text, _button, _labelR, _labelV);
-        topLevel.Add (menu, _win);
+
+        menu.Add (
+            new MenuBarItem (
+                "Padding",
+                [
+                    new MenuItem
+                    {
+                        Title = "With Padding",
+                        Action = () =>
+                        {
+                            if (_win is { })
+                            {
+                                _win.Padding!.Thickness = new (1);
+                            }
+                        }
+                    },
+                    new MenuItem
+                    {
+                        Title = "Without Padding",
+                        Action = () =>
+                        {
+                            if (_win is { })
+                            {
+                                _win.Padding!.Thickness = new (0);
+                            }
+                        }
+                    }
+                ]
+            )
+        );
+
+        menu.Add (
+            new MenuBarItem (
+                "BorderStyle",
+                [
+                    new MenuItem
+                    {
+                        Title = "Single",
+                        Action = () =>
+                        {
+                            if (_win is { })
+                            {
+                                _win.BorderStyle = LineStyle.Single;
+                            }
+                        }
+                    },
+                    new MenuItem
+                    {
+                        Title = "None",
+                        Action = () =>
+                        {
+                            if (_win is { })
+                            {
+                                _win.BorderStyle = LineStyle.None;
+                            }
+                        }
+                    }
+                ]
+            )
+        );
+
+        menu.Add (
+            new MenuBarItem (
+                "Runes length",
+                [
+                    new MenuItem
+                    {
+                        Title = "Wide",
+                        Action = WideRunes
+                    },
+                    new MenuItem
+                    {
+                        Title = "Narrow",
+                        Action = NarrowRunes
+                    },
+                    new MenuItem
+                    {
+                        Title = "Mixed",
+                        Action = MixedRunes
+                    }
+                ]
+            )
+        );
+
+        // Add views in order of visual appearance
+        win.Add (menu, _label, _text, _button, _labelR, _labelV);
 
         WideRunes ();
 
-        //NarrowRunes ();
-        //MixedRunes ();
-        Application.Run (topLevel);
-        topLevel.Dispose ();
+        Application.Run (win);
+        win.Dispose ();
         Application.Shutdown ();
     }
 
-    private void MixedMessage (object sender, EventArgs e) { MessageBox.Query ("Say Hello 你", $"Hello {_text.Text}", "Ok"); }
+    private void MixedMessage (object? sender, EventArgs e)
+    {
+        if (_text is { })
+        {
+            MessageBox.Query (ApplicationImpl.Instance, "Say Hello 你", $"Hello {_text.Text}", "Ok");
+        }
+    }
 
     private void MixedRunes ()
     {
+        if (_label is null || _text is null || _button is null || _labelR is null || _labelV is null || _win is null)
+        {
+            return;
+        }
+
         UnsetClickedEvent ();
         _label.Text = "Enter your name 你:";
         _text.Text = "gui.cs 你:";
@@ -117,10 +193,21 @@ public class RuneWidthGreaterThanOne : Scenario
         Application.LayoutAndDraw ();
     }
 
-    private void NarrowMessage (object sender, EventArgs e) { MessageBox.Query ("Say Hello", $"Hello {_text.Text}", "Ok"); }
+    private void NarrowMessage (object? sender, EventArgs e)
+    {
+        if (_text is { })
+        {
+            MessageBox.Query (ApplicationImpl.Instance, "Say Hello", $"Hello {_text.Text}", "Ok");
+        }
+    }
 
     private void NarrowRunes ()
     {
+        if (_label is null || _text is null || _button is null || _labelR is null || _labelV is null || _win is null)
+        {
+            return;
+        }
+
         UnsetClickedEvent ();
         _label.Text = "Enter your name:";
         _text.Text = "gui.cs";
@@ -139,6 +226,11 @@ public class RuneWidthGreaterThanOne : Scenario
 
     private void UnsetClickedEvent ()
     {
+        if (_button is null)
+        {
+            return;
+        }
+
         switch (_lastRunesUsed)
         {
             case "Narrow":
@@ -156,10 +248,21 @@ public class RuneWidthGreaterThanOne : Scenario
         }
     }
 
-    private void WideMessage (object sender, EventArgs e) { MessageBox.Query ("こんにちはと言う", $"こんにちは {_text.Text}", "Ok"); }
+    private void WideMessage (object? sender, EventArgs e)
+    {
+        if (_text is { })
+        {
+            MessageBox.Query (ApplicationImpl.Instance, "こんにちはと言う", $"こんにちは {_text.Text}", "Ok");
+        }
+    }
 
     private void WideRunes ()
     {
+        if (_label is null || _text is null || _button is null || _labelR is null || _labelV is null || _win is null)
+        {
+            return;
+        }
+
         UnsetClickedEvent ();
         _label.Text = "あなたの名前を入力してください:";
         _text.Text = "ティラミス";
@@ -175,4 +278,4 @@ public class RuneWidthGreaterThanOne : Scenario
         _lastRunesUsed = "Wide";
         Application.LayoutAndDraw ();
     }
-}
+}

+ 5 - 9
Examples/UICatalog/Scenarios/ScrollBarDemo.cs

@@ -118,23 +118,19 @@ public class ScrollBarDemo : Scenario
         };
         demoFrame.Add (lblOrientationLabel);
 
-        var rgOrientation = new RadioGroup
+        OptionSelector<Orientation> osOrientation = new ()
         {
             X = Pos.Right (lblOrientationLabel) + 1,
             Y = Pos.Top (lblOrientationLabel),
-            RadioLabels = ["Vertical", "Horizontal"],
+            AssignHotKeys = true,
             Orientation = Orientation.Horizontal
         };
-        demoFrame.Add (rgOrientation);
+        demoFrame.Add (osOrientation);
 
-        rgOrientation.SelectedItemChanged += (s, e) =>
+        osOrientation.ValueChanged += (s, e) =>
                                              {
-                                                 if (e.SelectedItem == e.PreviousSelectedItem)
-                                                 {
-                                                     return;
-                                                 }
 
-                                                 if (rgOrientation.SelectedItem == 0)
+                                                 if (osOrientation.Value == Orientation.Horizontal)
                                                  {
                                                      scrollBar.Orientation = Orientation.Vertical;
                                                      scrollBar.X = Pos.AnchorEnd () - 5;

+ 15 - 15
Examples/UICatalog/Scenarios/Scrolling.cs

@@ -16,13 +16,13 @@ public class Scrolling : Scenario
     {
         Application.Init ();
 
-        var app = new Window
+        var win = new Window
         {
             Title = GetQuitKeyAndName ()
         };
 
         var label = new Label { X = 0, Y = 0 };
-        app.Add (label);
+        win.Add (label);
 
         var demoView = new AllViewsView
         {
@@ -42,7 +42,7 @@ public class Scrolling : Scenario
                                             $"{demoView}\nContentSize: {demoView.GetContentSize ()}\nViewport.Location: {demoView.Viewport.Location}";
                                     };
 
-        app.Add (demoView);
+        win.Add (demoView);
 
         var hCheckBox = new CheckBox
         {
@@ -51,7 +51,7 @@ public class Scrolling : Scenario
             Text = "_HorizontalScrollBar.Visible",
             CheckedState = demoView.HorizontalScrollBar.Visible ? CheckState.Checked : CheckState.UnChecked
         };
-        app.Add (hCheckBox);
+        win.Add (hCheckBox);
         hCheckBox.CheckedStateChanged += (sender, args) => { demoView.HorizontalScrollBar.Visible = args.Value == CheckState.Checked; };
 
         var vCheckBox = new CheckBox
@@ -61,7 +61,7 @@ public class Scrolling : Scenario
             Text = "_VerticalScrollBar.Visible",
             CheckedState = demoView.VerticalScrollBar.Visible ? CheckState.Checked : CheckState.UnChecked
         };
-        app.Add (vCheckBox);
+        win.Add (vCheckBox);
         vCheckBox.CheckedStateChanged += (sender, args) => { demoView.VerticalScrollBar.Visible = args.Value == CheckState.Checked; };
 
         var ahCheckBox = new CheckBox
@@ -77,7 +77,7 @@ public class Scrolling : Scenario
                                                demoView.HorizontalScrollBar.AutoShow = e.Result == CheckState.Checked;
                                                demoView.VerticalScrollBar.AutoShow = e.Result == CheckState.Checked;
                                            };
-        app.Add (ahCheckBox);
+        win.Add (ahCheckBox);
 
         demoView.VerticalScrollBar.VisibleChanging += (sender, args) => { vCheckBox.CheckedState = args.NewValue ? CheckState.Checked : CheckState.UnChecked; };
 
@@ -92,19 +92,19 @@ public class Scrolling : Scenario
             X = Pos.Center (), Y = Pos.AnchorEnd (), Width = Dim.Fill ()
         };
 
-        app.Add (progress);
+        win.Add (progress);
 
-        app.Initialized += AppOnInitialized;
-        app.Unloaded += AppUnloaded;
+        win.Initialized += WinOnInitialized;
+        win.IsRunningChanged += WinIsRunningChanged;
 
-        Application.Run (app);
-        app.Unloaded -= AppUnloaded;
-        app.Dispose ();
+        Application.Run (win);
+        win.IsRunningChanged -= WinIsRunningChanged;
+        win.Dispose ();
         Application.Shutdown ();
 
         return;
 
-        void AppOnInitialized (object? sender, EventArgs e)
+        void WinOnInitialized (object? sender, EventArgs e)
         {
             bool TimerFn ()
             {
@@ -116,9 +116,9 @@ public class Scrolling : Scenario
             _progressTimer = Application.AddTimeout (TimeSpan.FromMilliseconds (200), TimerFn);
         }
 
-        void AppUnloaded (object? sender, EventArgs args)
+        void WinIsRunningChanged (object? sender, EventArgs<bool> args)
         {
-            if (_progressTimer is { })
+            if (!args.Value && _progressTimer is { })
             {
                 Application.RemoveTimeout (_progressTimer);
                 _progressTimer = null;

+ 287 - 0
Examples/UICatalog/Scenarios/Selectors.cs

@@ -0,0 +1,287 @@
+#nullable enable
+
+namespace UICatalog.Scenarios;
+
+[ScenarioMetadata ("Selectors", "Demonstrates OptionSelector and FlagSelector.")]
+[ScenarioCategory ("Controls")]
+public sealed class Selectors : Scenario
+{
+    public override void Main ()
+    {
+        // Init
+        Application.Init ();
+
+        // Setup - Create a top-level application window and configure it.
+        Window appWindow = new ()
+        {
+            Title = GetQuitKeyAndName (),
+            BorderStyle = LineStyle.None
+        };
+
+        FrameView? optionSelectorsFrame = null;
+        FrameView? flagSelectorsFrame = null;
+
+        OptionSelector<Orientation> orientationSelector = new ()
+        {
+            Orientation = Orientation.Horizontal,
+            BorderStyle = LineStyle.Dotted,
+            Title = "Selector Or_ientation",
+            Value = Orientation.Vertical
+        };
+        orientationSelector.ValueChanged += OrientationSelectorOnSelectedItemChanged;
+
+        FlagSelector<SelectorStyles> stylesSelector = new ()
+        {
+            X = Pos.Right (orientationSelector) + 1,
+            Orientation = Orientation.Horizontal,
+            BorderStyle = LineStyle.Dotted,
+            Title = "Selector St_yles",
+        };
+        stylesSelector.ValueChanged += StylesSelectorOnValueChanged;
+
+        NumericUpDown<int> horizontalSpace = new ()
+        {
+            X = 0,
+            Y = Pos.Bottom (orientationSelector),
+            Width = 11,
+            Title = "H_. Space",
+            Value = stylesSelector.HorizontalSpace,
+            BorderStyle = LineStyle.Dotted,
+        };
+        horizontalSpace.ValueChanging += HorizontalSpaceOnValueChanging;
+
+        CheckBox showBorderAndTitle = new ()
+        {
+            X = Pos.Right (horizontalSpace) + 1,
+            Y = Pos.Top (horizontalSpace),
+            Title = "Border _& Title",
+            CheckedState = CheckState.Checked,
+            BorderStyle = LineStyle.Dotted,
+        };
+        showBorderAndTitle.CheckedStateChanged += ShowBorderAndTitleOnCheckedStateChanged;
+
+        CheckBox canFocus = new ()
+        {
+            X = Pos.Right (showBorderAndTitle) + 1,
+            Y = Pos.Top (horizontalSpace),
+            Title = "_CanFocus",
+            CheckedState = CheckState.Checked,
+            BorderStyle = LineStyle.Dotted,
+        };
+        canFocus.CheckedStateChanged += CanFocusOnCheckedStateChanged;
+
+        optionSelectorsFrame = new ()
+        {
+            Y = Pos.Bottom (canFocus),
+            Width = Dim.Percent (50),
+            Height = Dim.Fill (),
+            Title = "O_ptionSelectors",
+            TabStop = TabBehavior.TabStop,
+            //InvertFocusAttribute = true
+        };
+        optionSelectorsFrame.ClearingViewport += (sender, args) =>
+                                                 {
+                                                     //               optionSelectorsFrame.SetAttributeForRole (optionSelectorsFrame.HasFocus ? VisualRole.Focus : VisualRole.Normal);
+                                                 };
+
+
+        Label label = new ()
+        {
+            Title = "Fo_ur Options:"
+        };
+
+        OptionSelector optionSelector = new ()
+        {
+            X = Pos.Right (label) + 1,
+            Title = "Fou_r Options",
+            BorderStyle = LineStyle.Dotted,
+            UsedHotKeys = { label.HotKey },
+            AssignHotKeys = true,
+            Labels = ["Option _1 (0)", "Option _2 (1)", "Option _3 (5) 你", "Option _Quattro (4) 你"],
+            Values = [0, 1, 5, 4],
+            Arrangement = ViewArrangement.Resizable,
+        };
+        optionSelectorsFrame.Add (label, optionSelector);
+
+        label = new ()
+        {
+            Y = Pos.Bottom (optionSelector),
+            Title = "<VisualRole_>:"
+        };
+
+        OptionSelector<VisualRole> optionSelectorT = new ()
+        {
+            X = Pos.Right (label) + 1,
+            Y = Pos.Bottom (optionSelector),
+            Title = "<Vi_sualRole>",
+            BorderStyle = LineStyle.Dotted,
+            UsedHotKeys = optionSelector.UsedHotKeys,
+            AssignHotKeys = true,
+        };
+
+        optionSelectorsFrame.Add (label, optionSelectorT);
+
+        flagSelectorsFrame = new ()
+        {
+            Y = Pos.Top (optionSelectorsFrame),
+            X = Pos.Right (optionSelectorsFrame),
+            Width = Dim.Fill (),
+            Height = Dim.Fill (),
+            Title = "_FlagSelectors",
+            TabStop = TabBehavior.TabStop
+        };
+
+        label = new ()
+        {
+            Title = "FlagSelector _(uint):"
+        };
+
+        FlagSelector flagSelector = new ()
+        {
+            X = Pos.Right (label) + 1,
+            UsedHotKeys = optionSelectorT.UsedHotKeys,
+            BorderStyle = LineStyle.Dotted,
+            Title = "FlagSe_lector (uint)",
+            AssignHotKeys = true,
+            Values =
+            [
+                0b_0001,
+                0b_0010,
+                0b_0100,
+                0b_1000,
+                0b_1111
+            ],
+            Labels =
+            [
+                "0x0001 One",
+                "0x0010 Two",
+                "0x0100 Quattro",
+                "0x1000 8",
+                "0x1111 Fifteen"
+            ]
+        };
+        flagSelectorsFrame.Add (label, flagSelector);
+
+        label = new ()
+        {
+            Y = Pos.Bottom (flagSelector),
+            Title = "_<ViewDiagnosticFlags>:"
+        };
+
+        FlagSelector<ViewDiagnosticFlags> flagSelectorT = new ()
+        {
+            X = Pos.Right (label) + 1,
+            BorderStyle = LineStyle.Dotted,
+            Title = "<ViewD_iagnosticFlags>",
+            Y = Pos.Bottom (flagSelector),
+            UsedHotKeys = flagSelector.UsedHotKeys,
+            AssignHotKeys = true,
+            Value = View.Diagnostics
+        };
+        flagSelectorsFrame.Add (label, flagSelectorT);
+        flagSelectorT.ValueChanged += (s, a) =>
+                                      {
+                                          View.Diagnostics = (ViewDiagnosticFlags)a.Value!;
+                                      };
+
+        appWindow.Add (orientationSelector, stylesSelector, horizontalSpace, showBorderAndTitle, canFocus, optionSelectorsFrame, flagSelectorsFrame);
+
+        // Run - Start the application.
+        Application.Run (appWindow);
+        appWindow.Dispose ();
+
+        // Shutdown - Calling Application.Shutdown is required.
+        Application.Shutdown ();
+
+        return;
+
+        void OrientationSelectorOnSelectedItemChanged (object? sender, EventArgs<Orientation?> e)
+        {
+            if (sender is not OptionSelector<Orientation> s)
+            {
+                return;
+            }
+
+            List<SelectorBase> selectors = GetAllSelectors ();
+            foreach (SelectorBase selector in selectors)
+            {
+                selector.Orientation = s.Value!.Value;
+            }
+        }
+
+        void StylesSelectorOnValueChanged (object? sender, EventArgs<SelectorStyles?> e)
+        {
+            if (sender is not FlagSelector<SelectorStyles> s)
+            {
+                return;
+            }
+
+            List<SelectorBase> selectors = GetAllSelectors ();
+
+            foreach (SelectorBase selector in selectors)
+            {
+                selector.Styles = s.Value!.Value;
+            }
+        }
+
+        void HorizontalSpaceOnValueChanging (object? sender, CancelEventArgs<int> e)
+        {
+            if (sender is not NumericUpDown<int> upDown || e.NewValue < 0)
+            {
+                e.Cancel = true;
+                return;
+            }
+
+            List<SelectorBase> selectors = GetAllSelectors ();
+
+            foreach (SelectorBase selector in selectors)
+            {
+                selector.HorizontalSpace = e.NewValue;
+            }
+        }
+
+
+        void ShowBorderAndTitleOnCheckedStateChanged (object? sender, EventArgs<CheckState> e)
+        {
+            if (sender is not CheckBox cb)
+            {
+                return;
+            }
+
+            List<SelectorBase> selectors = GetAllSelectors ();
+
+            foreach (SelectorBase selector in selectors)
+            {
+                selector.Border!.Thickness = cb.CheckedState == CheckState.Checked ? new (1) : new Thickness (0);
+            }
+        }
+
+        void CanFocusOnCheckedStateChanged (object? sender, EventArgs<CheckState> e)
+        {
+            if (sender is not CheckBox cb)
+            {
+                return;
+            }
+
+            List<SelectorBase> selectors = GetAllSelectors ();
+
+            foreach (SelectorBase selector in selectors)
+            {
+                selector.CanFocus = cb.CheckedState == CheckState.Checked;
+            }
+        }
+
+        List<SelectorBase> GetAllSelectors ()
+        {
+            List<SelectorBase> optionSelectors = [];
+            // ReSharper disable once AccessToModifiedClosure
+            optionSelectors.AddRange (optionSelectorsFrame!.SubViews.OfType<SelectorBase> ());
+            // ReSharper disable once AccessToModifiedClosure
+            optionSelectors.AddRange (flagSelectorsFrame!.SubViews.OfType<FlagSelector> ());
+
+            return optionSelectors;
+        }
+    }
+
+
+}

+ 127 - 90
Examples/UICatalog/Scenarios/Shortcuts.cs

@@ -15,7 +15,7 @@ public class Shortcuts : Scenario
         var quitKey = Application.QuitKey;
         Window app = new ();
 
-        app.Loaded += App_Loaded;
+        app.IsModalChanged += App_Loaded;
 
         Application.Run (app);
         app.Dispose ();
@@ -28,7 +28,7 @@ public class Shortcuts : Scenario
     private void App_Loaded (object? sender, EventArgs e)
     {
         Application.QuitKey = Key.F4.WithCtrl;
-        Application.Top!.Title = GetQuitKeyAndName ();
+        Application.TopRunnableView!.Title = GetQuitKeyAndName ();
 
         ObservableCollection<string> eventSource = new ();
 
@@ -38,7 +38,7 @@ public class Shortcuts : Scenario
             X = Pos.AnchorEnd (),
             Y = 0,
             Height = Dim.Fill (4),
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (eventSource),
             BorderStyle = LineStyle.Double,
             Title = "E_vents"
@@ -46,14 +46,14 @@ public class Shortcuts : Scenario
 
         eventLog.Width = Dim.Func (
                                    _ => Math.Min (
-                                                  Application.Top.Viewport.Width / 2,
+                                                  Application.TopRunnableView.Viewport.Width / 2,
                                                   eventLog?.MaxLength + eventLog!.GetAdornmentsThickness ().Horizontal ?? 0));
 
         eventLog.Width = Dim.Func (
                                    _ => Math.Min (
                                                   eventLog.SuperView!.Viewport.Width / 2,
                                                   eventLog?.MaxLength + eventLog!.GetAdornmentsThickness ().Horizontal ?? 0));
-        Application.Top.Add (eventLog);
+        Application.TopRunnableView.Add (eventLog);
 
         var alignKeysShortcut = new Shortcut
         {
@@ -66,48 +66,27 @@ public class Shortcuts : Scenario
             {
                 Text = "_Align Keys",
                 CanFocus = false,
-                HighlightStates = MouseState.None
+                HighlightStates = MouseState.None,
+                CheckedState = CheckState.Checked
             },
             Key = Key.F5.WithCtrl.WithAlt.WithShift
         };
 
-        // ((CheckBox)vShortcut3.CommandView).CheckedStateChanging += (_, args) =>
         ((CheckBox)alignKeysShortcut.CommandView).CheckedStateChanging += (s, e) =>
                                                                           {
                                                                               if (alignKeysShortcut.CommandView is CheckBox cb)
                                                                               {
+                                                                                  bool align = e.Result == CheckState.Checked;
                                                                                   eventSource.Add (
                                                                                                    $"{alignKeysShortcut.Id}.CommandView.CheckedStateChanging: {cb.Text}");
                                                                                   eventLog.MoveDown ();
 
-                                                                                  var max = 0;
-
-                                                                                  IEnumerable<View> toAlign =
-                                                                                      Application.Top.SubViews.Where (
-                                                                                       v => v is Shortcut { Width: not DimAbsolute });
-                                                                                  IEnumerable<View> enumerable = toAlign as View [] ?? toAlign.ToArray ();
-
-                                                                                  if (e.Result == CheckState.Checked)
-                                                                                  {
-                                                                                      max = (from Shortcut? peer in enumerable
-                                                                                             select peer.Key.ToString ().GetColumns ()).Prepend (max)
-                                                                                          .Max ();
-
-                                                                                      foreach (View view in enumerable)
-                                                                                      {
-                                                                                          var peer = (Shortcut)view;
-                                                                                          max = Math.Max (max, peer.KeyView.Text.GetColumns ());
-                                                                                      }
-                                                                                  }
-
-                                                                                  foreach (View view in enumerable)
-                                                                                  {
-                                                                                      var peer = (Shortcut)view;
-                                                                                      peer.MinimumKeyTextSize = max;
-                                                                                  }
+                                                                                  AlignKeys (align);
                                                                               }
                                                                           };
-        Application.Top.Add (alignKeysShortcut);
+
+
+        Application.TopRunnableView.Add (alignKeysShortcut);
 
         var commandFirstShortcut = new Shortcut
         {
@@ -136,9 +115,7 @@ public class Shortcuts : Scenario
                                                                                                       $"{commandFirstShortcut.Id}.CommandView.CheckedStateChanging: {cb.Text}");
                                                                                      eventLog.MoveDown ();
 
-                                                                                     IEnumerable<View> toAlign =
-                                                                                         Application.Top.SubViews.Where (
-                                                                                          v => v is Shortcut { Width: not DimAbsolute });
+                                                                                     IEnumerable<View> toAlign = Application.TopRunnableView.SubViews.OfType<Shortcut> ();
                                                                                      IEnumerable<View> enumerable = toAlign as View [] ?? toAlign.ToArray ();
 
                                                                                      foreach (View view in enumerable)
@@ -157,7 +134,7 @@ public class Shortcuts : Scenario
                                                                                  }
                                                                              };
 
-        Application.Top.Add (commandFirstShortcut);
+        Application.TopRunnableView.Add (commandFirstShortcut);
 
         var canFocusShortcut = new Shortcut
         {
@@ -166,8 +143,8 @@ public class Shortcuts : Scenario
             Y = Pos.Bottom (commandFirstShortcut),
             Width = Dim.Fill ()! - Dim.Width (eventLog),
             Key = Key.F4,
-            HelpText = "Changes all Command.CanFocus",
-            CommandView = new CheckBox { Text = "_CanFocus" }
+            HelpText = "Changes all CommandView.CanFocus",
+            CommandView = new CheckBox { Text = "_CommandView.CanFocus" },
         };
 
         ((CheckBox)canFocusShortcut.CommandView).CheckedStateChanging += (s, e) =>
@@ -179,16 +156,10 @@ public class Shortcuts : Scenario
 
                                                                                  //cb.CanFocus = e.NewValue == CheckState.Checked;
 
-                                                                                 foreach (Shortcut peer in Application.Top.SubViews.Where (v => v is Shortcut)!)
-                                                                                 {
-                                                                                     if (peer.CanFocus)
-                                                                                     {
-                                                                                         peer.CommandView.CanFocus = e.Result == CheckState.Checked;
-                                                                                     }
-                                                                                 }
+                                                                                 SetCanFocus (e.Result == CheckState.Checked);
                                                                              }
                                                                          };
-        Application.Top.Add (canFocusShortcut);
+        Application.TopRunnableView.Add (canFocusShortcut);
 
         var appShortcut = new Shortcut
         {
@@ -202,7 +173,7 @@ public class Shortcuts : Scenario
             BindKeyToApplication = true
         };
 
-        Application.Top.Add (appShortcut);
+        Application.TopRunnableView.Add (appShortcut);
 
         var buttonShortcut = new Shortcut
         {
@@ -222,39 +193,41 @@ public class Shortcuts : Scenario
         var button = (Button)buttonShortcut.CommandView;
         buttonShortcut.Accepting += Button_Clicked;
 
-        Application.Top.Add (buttonShortcut);
+        Application.TopRunnableView.Add (buttonShortcut);
 
-        var radioGroupShortcut = new Shortcut
+        var optionSelectorShortcut = new Shortcut
         {
-            Id = "radioGroupShortcut",
+            Id = "optionSelectorShortcut",
+            HelpText = "Option Selector",
             X = 0,
             Y = Pos.Bottom (buttonShortcut),
             Key = Key.F2,
             Width = Dim.Fill ()! - Dim.Width (eventLog),
-            CommandView = new RadioGroup
+            CommandView = new OptionSelector ()
             {
                 Orientation = Orientation.Vertical,
-                RadioLabels = ["O_ne", "T_wo", "Th_ree", "Fo_ur"]
-            }
+                Labels = ["O_ne", "T_wo", "Th_ree", "Fo_ur"],
+                HighlightStates = MouseState.None,
+            },
         };
 
-        ((RadioGroup)radioGroupShortcut.CommandView).SelectedItemChanged += (o, args) =>
-                                                                            {
-                                                                                if (o is { })
+        ((OptionSelector)optionSelectorShortcut.CommandView).ValueChanged += (o, args) =>
                                                                                 {
-                                                                                    eventSource.Add (
-                                                                                                     $"SelectedItemChanged: {o.GetType ().Name} - {args.SelectedItem}");
-                                                                                    eventLog.MoveDown ();
-                                                                                }
-                                                                            };
+                                                                                    if (o is { })
+                                                                                    {
+                                                                                        eventSource.Add (
+                                                                                                         $"ValueChanged: {o.GetType ().Name} - {args.Value}");
+                                                                                        eventLog.MoveDown ();
+                                                                                    }
+                                                                                };
 
-        Application.Top.Add (radioGroupShortcut);
+        Application.TopRunnableView.Add (optionSelectorShortcut);
 
         var sliderShortcut = new Shortcut
         {
             Id = "sliderShortcut",
             X = 0,
-            Y = Pos.Bottom (radioGroupShortcut),
+            Y = Pos.Bottom (optionSelectorShortcut),
             Width = Dim.Fill ()! - Dim.Width (eventLog),
             HelpText = "Sliders work!",
             CommandView = new Slider<string>
@@ -275,19 +248,41 @@ public class Shortcuts : Scenario
                                                                            eventLog.MoveDown ();
                                                                        };
 
-        Application.Top.Add (sliderShortcut);
+        Application.TopRunnableView.Add (sliderShortcut);
+
+        ListView listView = new ListView ()
+        {
+            Height = Dim.Auto (),
+            Width = Dim.Auto (),
+            Title = "ListView",
+            BorderStyle = LineStyle.Single
+        };
+        listView.EnableForDesign ();
+
+        var listViewShortcut = new Shortcut ()
+        {
+            Id = "listViewShortcut",
+            X = 0,
+            Y = Pos.Bottom (sliderShortcut),
+            Width = Dim.Fill ()! - Dim.Width (eventLog),
+            HelpText = "A ListView with Border",
+            CommandView = listView,
+            Key = Key.F5.WithCtrl,
+        };
+
+        Application.TopRunnableView.Add (listViewShortcut);
 
         var noCommandShortcut = new Shortcut
         {
             Id = "noCommandShortcut",
             X = 0,
-            Y = Pos.Bottom (sliderShortcut),
-            Width = Dim.Width (sliderShortcut),
+            Y = Pos.Bottom (listViewShortcut),
+            Width = Dim.Width (listViewShortcut),
             HelpText = "No Command",
             Key = Key.D0
         };
 
-        Application.Top.Add (noCommandShortcut);
+        Application.TopRunnableView.Add (noCommandShortcut);
 
         var noKeyShortcut = new Shortcut
         {
@@ -300,7 +295,7 @@ public class Shortcuts : Scenario
             HelpText = "Keyless"
         };
 
-        Application.Top.Add (noKeyShortcut);
+        Application.TopRunnableView.Add (noKeyShortcut);
 
         var noHelpShortcut = new Shortcut
         {
@@ -313,7 +308,7 @@ public class Shortcuts : Scenario
             HelpText = ""
         };
 
-        Application.Top.Add (noHelpShortcut);
+        Application.TopRunnableView.Add (noHelpShortcut);
         noHelpShortcut.SetFocus ();
 
         var framedShortcut = new Shortcut
@@ -321,13 +316,15 @@ public class Shortcuts : Scenario
             Id = "framedShortcut",
             X = 0,
             Y = Pos.Bottom (noHelpShortcut) + 1,
-            Title = "Framed",
+            Width = Dim.Width (noHelpShortcut),
+            Title = "Framed Shortcut",
             Key = Key.K.WithCtrl,
-            Text = "Resize frame",
+            Text = "Help: You can resize this",
             BorderStyle = LineStyle.Dotted,
             Arrangement = ViewArrangement.RightResizable | ViewArrangement.BottomResizable
         };
-        framedShortcut.Orientation = Orientation.Horizontal;
+        framedShortcut.Border!.Settings = BorderSettings.Title;
+        //framedShortcut.Orientation = Orientation.Horizontal;
 
         if (framedShortcut.Padding is { })
         {
@@ -337,13 +334,13 @@ public class Shortcuts : Scenario
 
         if (framedShortcut.CommandView.Margin is { })
         {
-            framedShortcut.CommandView.Margin.SchemeName = framedShortcut.CommandView.SchemeName = "Error";
-            framedShortcut.HelpView.Margin!.SchemeName = framedShortcut.HelpView.SchemeName = "Dialog";
-            framedShortcut.KeyView.Margin!.SchemeName = framedShortcut.KeyView.SchemeName = "Menu";
+            framedShortcut.CommandView.SchemeName = framedShortcut.CommandView.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Dialog);
+            framedShortcut.HelpView.SchemeName = framedShortcut.HelpView.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Error);
+            framedShortcut.KeyView.SchemeName = framedShortcut.KeyView.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Base);
         }
 
-        framedShortcut.SchemeName = "TopLevel";
-        Application.Top.Add (framedShortcut);
+        framedShortcut.SchemeName = SchemeManager.SchemesToSchemeName (Schemes.Runnable);
+        Application.TopRunnableView.Add (framedShortcut);
 
         // Horizontal
         var progressShortcut = new Shortcut
@@ -390,7 +387,7 @@ public class Shortcuts : Scenario
                          };
         timer.Start ();
 
-        Application.Top.Add (progressShortcut);
+        Application.TopRunnableView.Add (progressShortcut);
 
         var textField = new TextField
         {
@@ -411,7 +408,7 @@ public class Shortcuts : Scenario
         };
         textField.CanFocus = true;
 
-        Application.Top.Add (textFieldShortcut);
+        Application.TopRunnableView.Add (textFieldShortcut);
 
         var bgColorShortcut = new Shortcut
         {
@@ -453,19 +450,19 @@ public class Shortcuts : Scenario
                                         eventSource.Add ($"ColorChanged: {o.GetType ().Name} - {args.Result}");
                                         eventLog.MoveDown ();
 
-                                        Application.Top.SetScheme (
-                                                                   new (Application.Top.GetScheme ())
+                                        Application.TopRunnableView.SetScheme (
+                                                                   new (Application.TopRunnableView.GetScheme ())
                                                                    {
                                                                        Normal = new (
-                                                                                     Application.Top!.GetAttributeForRole (VisualRole.Normal).Foreground,
+                                                                                     Application.TopRunnableView!.GetAttributeForRole (VisualRole.Normal).Foreground,
                                                                                      args.Result,
-                                                                                     Application.Top!.GetAttributeForRole (VisualRole.Normal).Style)
+                                                                                     Application.TopRunnableView!.GetAttributeForRole (VisualRole.Normal).Style)
                                                                    });
                                     }
                                 };
         bgColorShortcut.CommandView = bgColor;
 
-        Application.Top.Add (bgColorShortcut);
+        Application.TopRunnableView.Add (bgColorShortcut);
 
         var appQuitShortcut = new Shortcut
         {
@@ -479,9 +476,9 @@ public class Shortcuts : Scenario
         };
         appQuitShortcut.Accepting += (o, args) => { Application.RequestStop (); };
 
-        Application.Top.Add (appQuitShortcut);
+        Application.TopRunnableView.Add (appQuitShortcut);
 
-        foreach (Shortcut shortcut in Application.Top.SubViews.OfType<Shortcut> ())
+        foreach (Shortcut shortcut in Application.TopRunnableView.SubViews.OfType<Shortcut> ())
         {
             shortcut.Selecting += (o, args) =>
                                   {
@@ -504,7 +501,7 @@ public class Shortcuts : Scenario
                                                   eventSource.Add (
                                                                    $"{shortcut!.Id}.CommandView.Selecting: {shortcut!.CommandView.Text} {shortcut!.CommandView.GetType ().Name}");
                                                   eventLog.MoveDown ();
-                                                  args.Handled = true;
+                                                  //args.Handled = true;
                                               };
 
             shortcut.Accepting += (o, args) =>
@@ -513,7 +510,7 @@ public class Shortcuts : Scenario
                                       eventLog.MoveDown ();
 
                                       // We don't want this to exit the Scenario
-                                      args.Handled = true;
+                                      //args.Handled = true;
                                   };
 
             shortcut.CommandView.Accepting += (o, args) =>
@@ -523,12 +520,52 @@ public class Shortcuts : Scenario
                                                   eventLog.MoveDown ();
                                               };
         }
+
+        SetCanFocus (false);
+
+        AlignKeys (true);
+
+        return;
+
+        void SetCanFocus (bool canFocus)
+        {
+            foreach (Shortcut peer in Application.TopRunnableView!.SubViews.OfType<Shortcut> ())
+            {
+                if (peer.CanFocus)
+                {
+                    peer.CommandView.CanFocus = canFocus;
+                }
+            }
+        }
+
+        void AlignKeys (bool align)
+        {
+            var max = 0;
+
+            IEnumerable<Shortcut> toAlign = Application.TopRunnableView!.SubViews.OfType<Shortcut> ().Where(s => !s.Y.Has<PosAnchorEnd>(out _)).Cast<Shortcut>();
+            IEnumerable<Shortcut> enumerable = toAlign as Shortcut [] ?? toAlign.ToArray ();
+
+            if (align)
+            {
+                max = (from Shortcut? peer in enumerable
+                       select peer!.Key.ToString ().GetColumns ()).Prepend (max)
+                                                                  .Max ();
+
+                max = enumerable.Select (peer => peer.KeyView.Text.GetColumns ()).Prepend (max).Max ();
+            }
+
+            foreach (Shortcut shortcut in enumerable)
+            {
+                Shortcut peer = shortcut;
+                peer.MinimumKeyTextSize = max;
+            }
+        }
     }
 
     private void Button_Clicked (object? sender, CommandEventArgs e)
     {
         e.Handled = true;
         var view = sender as View;
-        MessageBox.Query ("Hi", $"You clicked {view?.Text}", "_Ok");
+        MessageBox.Query ((sender as View)?.App, "Hi", $"You clicked {view?.Text}", "_Ok");
     }
 }

+ 126 - 117
Examples/UICatalog/Scenarios/SingleBackgroundWorker.cs

@@ -1,12 +1,11 @@
-using System;
-using System.Collections.Generic;
+#nullable enable
+
 using System.Collections.ObjectModel;
 using System.ComponentModel;
-using System.Threading;
 
 namespace UICatalog.Scenarios;
 
-[ScenarioMetadata ("Single BackgroundWorker", "A single BackgroundWorker threading opening another Toplevel")]
+[ScenarioMetadata ("Single BackgroundWorker", "A single BackgroundWorker threading opening another Runnable")]
 [ScenarioCategory ("Threading")]
 [ScenarioCategory ("Arrangement")]
 [ScenarioCategory ("Runnable")]
@@ -14,58 +13,56 @@ public class SingleBackgroundWorker : Scenario
 {
     public override void Main ()
     {
-        Application.Run<MainApp> ().Dispose ();
+        Application.Run<MainApp> ();
         Application.Shutdown ();
     }
 
-    public class MainApp : Toplevel
+    public class MainApp : Window
     {
         private readonly ListView _listLog;
         private readonly ObservableCollection<string> _log = [];
         private DateTime? _startStaging;
-        private BackgroundWorker _worker;
+        private BackgroundWorker? _worker;
 
         public MainApp ()
         {
-            var menu = new MenuBar
-            {
-                Menus =
-                [
-                    new (
-                         "_Options",
-                         new MenuItem []
-                         {
-                             new (
-                                  "_Run Worker",
-                                  "",
-                                  () => RunWorker (),
-                                  null,
-                                  null,
-                                  KeyCode.CtrlMask | KeyCode.R
-                                 ),
-                             null,
-                             new (
-                                  "_Quit",
-                                  "",
-                                  () => Application.RequestStop (),
-                                  null,
-                                  null,
-                                  Application.QuitKey
-                                 )
-                         }
-                        )
-                ]
-            };
-
-            var statusBar = new StatusBar (
-                                           [
-                                               new (Application.QuitKey, "Quit", () => Application.RequestStop ()),
-                                               new (Key.R.WithCtrl, "Run Worker", RunWorker)
-                                           ]);
-
-            var workerLogTop = new Toplevel
+            BorderStyle = LineStyle.None;
+            // MenuBar
+            MenuBar menu = new ();
+
+            menu.Add (
+                      new MenuBarItem (
+                                       "_Options",
+                                       [
+                                           new MenuItem
+                                           {
+                                               Title = "_Run Worker",
+                                               Key = Key.R.WithCtrl,
+                                               Action = RunWorker
+                                           },
+                                           new MenuItem
+                                           {
+                                               Title = "_Quit",
+                                               Key = Application.QuitKey,
+                                               Action = () => Application.RequestStop ()
+                                           }
+                                       ]
+                                      )
+                     );
+
+            // StatusBar
+            StatusBar statusBar = new (
+                                       [
+                                           new (Application.QuitKey, "Quit", () => Application.RequestStop ()),
+                                           new (Key.R.WithCtrl, "Run Worker", RunWorker)
+                                       ]
+                                      );
+
+            Window workerLogTop = new ()
             {
-                Title = "Worker Log Top"
+                Title = "Worker Log Top",
+                Y = Pos.Bottom (menu),
+                Height = Dim.Fill (1)
             };
 
             workerLogTop.Add (
@@ -82,9 +79,6 @@ public class SingleBackgroundWorker : Scenario
             };
             workerLogTop.Add (_listLog);
 
-            workerLogTop.Y = 1;
-            workerLogTop.Height = Dim.Fill (Dim.Func (_ => statusBar.Frame.Height));
-
             Add (menu, workerLogTop, statusBar);
             Title = "MainApp";
         }
@@ -93,11 +87,11 @@ public class SingleBackgroundWorker : Scenario
         {
             _worker = new () { WorkerSupportsCancellation = true };
 
-            var cancel = new Button { Text = "Cancel Worker" };
+            Button cancel = new () { Text = "Cancel Worker" };
 
             cancel.Accepting += (s, e) =>
                                 {
-                                    if (_worker == null)
+                                    if (_worker is null)
                                     {
                                         _log.Add ($"Worker is not running at {DateTime.Now}!");
                                         _listLog.SetNeedsDraw ();
@@ -116,9 +110,10 @@ public class SingleBackgroundWorker : Scenario
             _log.Add ($"Worker is started at {_startStaging}.{_startStaging:fff}");
             _listLog.SetNeedsDraw ();
 
-            var md = new Dialog
+            Dialog md = new ()
             {
-                Title = $"Running Worker started at {_startStaging}.{_startStaging:fff}", Buttons = [cancel]
+                Title = $"Running Worker started at {_startStaging}.{_startStaging:fff}",
+                Buttons = [cancel]
             };
 
             md.Add (
@@ -127,7 +122,7 @@ public class SingleBackgroundWorker : Scenario
 
             _worker.DoWork += (s, e) =>
                               {
-                                  List<string> stageResult = new ();
+                                  List<string> stageResult = [];
 
                                   for (var i = 0; i < 200; i++)
                                   {
@@ -135,7 +130,7 @@ public class SingleBackgroundWorker : Scenario
                                       e.Result = stageResult;
                                       Thread.Sleep (1);
 
-                                      if (_worker.CancellationPending)
+                                      if (_worker?.CancellationPending == true)
                                       {
                                           e.Cancel = true;
 
@@ -152,7 +147,7 @@ public class SingleBackgroundWorker : Scenario
                                                   Application.RequestStop ();
                                               }
 
-                                              if (e.Error != null)
+                                              if (e.Error is { })
                                               {
                                                   // Failed
                                                   _log.Add (
@@ -177,14 +172,22 @@ public class SingleBackgroundWorker : Scenario
                                                   _listLog.SetNeedsDraw ();
                                                   Application.LayoutAndDraw ();
 
-                                                  var builderUI =
-                                                      new StagingUIController (_startStaging, e.Result as ObservableCollection<string>);
-                                                  Toplevel top = Application.Top;
-                                                  top.Visible = false;
-                                                  Application.Top.Visible = false;
+                                                  StagingUIController builderUI =
+                                                      new (_startStaging, e.Result as ObservableCollection<string>);
+                                                  View? top = Application.TopRunnableView;
+
+                                                  if (top is { })
+                                                  {
+                                                      top.Visible = false;
+                                                  }
+
                                                   builderUI.Load ();
                                                   builderUI.Dispose ();
-                                                  top.Visible = true;
+
+                                                  if (top is { })
+                                                  {
+                                                      top.Visible = true;
+                                                  }
                                               }
 
                                               _worker = null;
@@ -197,13 +200,15 @@ public class SingleBackgroundWorker : Scenario
 
     public class StagingUIController : Window
     {
-        private Toplevel _top;
+        private Runnable? _top;
 
-        public StagingUIController (DateTime? start, ObservableCollection<string> list)
+        public StagingUIController (DateTime? start, ObservableCollection<string>? list)
         {
             _top = new ()
             {
-                Title = "_top", Width = Dim.Fill (), Height = Dim.Fill (), Modal = true
+                Title = "_top",
+                Width = Dim.Fill (),
+                Height = Dim.Fill (),
             };
 
             _top.KeyDown += (s, e) =>
@@ -218,7 +223,7 @@ public class SingleBackgroundWorker : Scenario
 
             bool Close ()
             {
-                int n = MessageBox.Query (
+                int? n = MessageBox.Query (App,
                                           50,
                                           7,
                                           "Close Window.",
@@ -230,74 +235,78 @@ public class SingleBackgroundWorker : Scenario
                 return n == 0;
             }
 
-            var menu = new MenuBar
-            {
-                Menus =
-                [
-                    new (
-                         "_Stage",
-                         new MenuItem []
-                         {
-                             new (
-                                  "_Close",
-                                  "",
-                                  () =>
-                                  {
-                                      if (Close ())
-                                      {
-                                          Application.RequestStop ();
-                                      }
-                                  },
-                                  null,
-                                  null,
-                                  KeyCode.CtrlMask | KeyCode.C
-                                 )
-                         }
-                        )
-                ]
-            };
+            // MenuBar
+            MenuBar menu = new ();
+
+            menu.Add (
+                      new MenuBarItem (
+                                       "_Stage",
+                                       [
+                                           new MenuItem
+                                           {
+                                               Title = "_Close",
+                                               Key = Key.C.WithCtrl,
+                                               Action = () =>
+                                                        {
+                                                            if (Close ())
+                                                            {
+                                                                App?.RequestStop ();
+                                                            }
+                                                        }
+                                           }
+                                       ]
+                                      )
+                     );
             _top.Add (menu);
 
-            var statusBar = new StatusBar (
-                                           [
-                                               new (
-                                                    Key.C.WithCtrl,
-                                                    "Close",
-                                                    () =>
+            // StatusBar
+            StatusBar statusBar = new (
+                                       [
+                                           new (
+                                                Key.C.WithCtrl,
+                                                "Close",
+                                                () =>
+                                                {
+                                                    if (Close ())
                                                     {
-                                                        if (Close ())
-                                                        {
-                                                            Application.RequestStop ();
-                                                        }
+                                                        App?.RequestStop ();
                                                     }
-                                                   )
-                                           ]);
+                                                }
+                                               )
+                                       ]
+                                      );
             _top.Add (statusBar);
 
-            Y = 1;
+            Y = Pos.Bottom (menu);
             Height = Dim.Fill (1);
             Title = $"Worker started at {start}.{start:fff}";
             SchemeName = "Base";
 
-            Add (
-                 new ListView
-                 {
-                     X = 0,
-                     Y = 0,
-                     Width = Dim.Fill (),
-                     Height = Dim.Fill (),
-                     Source = new ListWrapper<string> (list)
-                 }
-                );
+            if (list is { })
+            {
+                Add (
+                     new ListView
+                     {
+                         X = 0,
+                         Y = 0,
+                         Width = Dim.Fill (),
+                         Height = Dim.Fill (),
+                         Source = new ListWrapper<string> (list)
+                     }
+                    );
+            }
 
             _top.Add (this);
         }
 
         public void Load ()
         {
-            Application.Run (_top);
-            _top.Dispose ();
-            _top = null;
+            if (_top is { })
+            {
+                App?.Run (_top);
+                _top.Dispose ();
+                _top = null;
+            }
         }
     }
 }

+ 9 - 9
Examples/UICatalog/Scenarios/Sliders.cs

@@ -86,17 +86,17 @@ public class Sliders : Scenario
                                 {
                                     if (single.Orientation == Orientation.Horizontal)
                                     {
-                                        single.Style.SpaceChar = new () { Rune = Glyphs.HLine };
-                                        single.Style.OptionChar = new () { Rune = Glyphs.HLine };
+                                        single.Style.SpaceChar = new () { Grapheme = Glyphs.HLine.ToString () };
+                                        single.Style.OptionChar = new () { Grapheme = Glyphs.HLine.ToString () };
                                     }
                                     else
                                     {
-                                        single.Style.SpaceChar = new () { Rune = Glyphs.VLine };
-                                        single.Style.OptionChar = new () { Rune = Glyphs.VLine };
+                                        single.Style.SpaceChar = new () { Grapheme = Glyphs.VLine.ToString () };
+                                        single.Style.OptionChar = new () { Grapheme = Glyphs.VLine.ToString () };
                                     }
                                 };
-        single.Style.SetChar = new () { Rune = Glyphs.ContinuousMeterSegment };
-        single.Style.DragChar = new () { Rune = Glyphs.ContinuousMeterSegment };
+        single.Style.SetChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () };
+        single.Style.DragChar = new () { Grapheme = Glyphs.ContinuousMeterSegment.ToString () };
 
         v.Add (single);
 
@@ -257,7 +257,7 @@ public class Sliders : Scenario
                                                     {
                                                         s.Orientation = Orientation.Horizontal;
 
-                                                        s.Style.SpaceChar = new () { Rune = Glyphs.HLine };
+                                                        s.Style.SpaceChar = new () { Grapheme = Glyphs.HLine.ToString () };
 
                                                         if (prev == null)
                                                         {
@@ -275,7 +275,7 @@ public class Sliders : Scenario
                                                     {
                                                         s.Orientation = Orientation.Vertical;
 
-                                                        s.Style.SpaceChar = new () { Rune = Glyphs.VLine };
+                                                        s.Style.SpaceChar = new () { Grapheme = Glyphs.VLine.ToString () };
 
                                                         if (prev == null)
                                                         {
@@ -590,7 +590,7 @@ public class Sliders : Scenario
             Y = Pos.Bottom (spacingOptions),
             Width = Dim.Fill (),
             Height = Dim.Fill (),
-            SchemeName = "TopLevel",
+            SchemeName = "Runnable",
             Source = new ListWrapper<string> (eventSource)
         };
         configView.Add (eventLog);

+ 18 - 18
Examples/UICatalog/Scenarios/SpinnerStyles.cs

@@ -14,7 +14,7 @@ public class SpinnerViewStyles : Scenario
     {
         Application.Init ();
 
-        Window app = new ()
+        Window win = new ()
         {
             Title = GetQuitKeyAndName ()
         };
@@ -40,7 +40,7 @@ public class SpinnerViewStyles : Scenario
             //Title = "Preview",
             BorderStyle = LineStyle.Single
         };
-        app.Add (preview);
+        win.Add (preview);
 
         var spinner = new SpinnerView { X = Pos.Center (), Y = 0 };
         preview.Add (spinner);
@@ -54,7 +54,7 @@ public class SpinnerViewStyles : Scenario
             CheckedState = CheckState.Checked,
             Text = "Ascii Only"
         };
-        app.Add (ckbAscii);
+        win.Add (ckbAscii);
 
         var ckbNoSpecial = new CheckBox
         {
@@ -64,28 +64,28 @@ public class SpinnerViewStyles : Scenario
             CheckedState = CheckState.Checked,
             Text = "No Special"
         };
-        app.Add (ckbNoSpecial);
+        win.Add (ckbNoSpecial);
 
         var ckbReverse = new CheckBox
         {
             X = Pos.Center () - 22, Y = Pos.Bottom (preview) + 1, CheckedState = CheckState.UnChecked, Text = "Reverse"
         };
-        app.Add (ckbReverse);
+        win.Add (ckbReverse);
 
         var ckbBounce = new CheckBox
         {
             X = Pos.Right (ckbReverse) + 2, Y = Pos.Bottom (preview) + 1, CheckedState = CheckState.UnChecked, Text = "Bounce"
         };
-        app.Add (ckbBounce);
+        win.Add (ckbBounce);
 
         var delayLabel = new Label { X = Pos.Right (ckbBounce) + 2, Y = Pos.Bottom (preview) + 1, Text = "Delay:" };
-        app.Add (delayLabel);
+        win.Add (delayLabel);
 
         var delayField = new TextField
         {
             X = Pos.Right (delayLabel), Y = Pos.Bottom (preview) + 1, Width = 5, Text = DEFAULT_DELAY.ToString ()
         };
-        app.Add (delayField);
+        win.Add (delayField);
 
         delayField.TextChanged += (s, e) =>
                                   {
@@ -96,13 +96,13 @@ public class SpinnerViewStyles : Scenario
                                   };
 
         var customLabel = new Label { X = Pos.Right (delayField) + 2, Y = Pos.Bottom (preview) + 1, Text = "Custom:" };
-        app.Add (customLabel);
+        win.Add (customLabel);
 
         var customField = new TextField
         {
             X = Pos.Right (customLabel), Y = Pos.Bottom (preview) + 1, Width = 12, Text = DEFAULT_CUSTOM
         };
-        app.Add (customField);
+        win.Add (customField);
 
         string [] styleArray = styleDict.Select (e => e.Value.Key).ToArray ();
 
@@ -117,7 +117,7 @@ public class SpinnerViewStyles : Scenario
         };
         styles.SetSource (new ObservableCollection<string> (styleArray));
         styles.SelectedItem = 0; // SpinnerStyle.Custom;
-        app.Add (styles);
+        win.Add (styles);
         SetCustom ();
 
         customField.TextChanged += (s, e) =>
@@ -153,7 +153,7 @@ public class SpinnerViewStyles : Scenario
                                           else
                                           {
                                               spinner.Visible = true;
-                                              spinner.Style = (SpinnerStyle)Activator.CreateInstance (styleDict [e.Item].Value);
+                                              spinner.Style = (SpinnerStyle)Activator.CreateInstance (styleDict [e.Item.Value].Value);
                                               delayField.Text = spinner.SpinDelay.ToString ();
                                               ckbBounce.CheckedState = spinner.SpinBounce ? CheckState.Checked : CheckState.UnChecked;
                                               ckbNoSpecial.CheckedState = !spinner.HasSpecialCharacters ? CheckState.Checked : CheckState.UnChecked;
@@ -166,7 +166,7 @@ public class SpinnerViewStyles : Scenario
 
         ckbBounce.CheckedStateChanging += (s, e) => { spinner.SpinBounce = e.Result == CheckState.Checked; };
 
-        app.Unloaded += App_Unloaded;
+        win.IsRunningChanged += WinIsRunningChanged;
 
         void SetCustom ()
         {
@@ -199,23 +199,23 @@ public class SpinnerViewStyles : Scenario
             }
         }
 
-        void App_Unloaded (object sender, EventArgs args)
+        void WinIsRunningChanged (object sender, EventArgs<bool> args)
         {
-            if (spinner is {})
+            if (!args.Value && spinner is {})
             {
                 spinner.Dispose ();
                 spinner = null;
             }
         }
 
-        Application.Run (app);
-        app.Unloaded -= App_Unloaded;
+        Application.Run (win);
+        win.IsRunningChanged -= WinIsRunningChanged;
         if (spinner is { })
         {
             spinner.Dispose ();
             spinner = null;
         }
-        app.Dispose ();
+        win.Dispose ();
 
         Application.Shutdown ();
     }

+ 58 - 65
Examples/UICatalog/Scenarios/SyntaxHighlighting.cs

@@ -1,8 +1,4 @@
-using System;
-using System.Collections.Generic;
-using System.ComponentModel;
-using System.IO;
-using System.Linq;
+using System.ComponentModel;
 using System.Reflection;
 using System.Text;
 using System.Text.Json;
@@ -88,7 +84,6 @@ public class SyntaxHighlighting : Scenario
     private Attribute _blue;
     private Attribute _green;
     private Attribute _magenta;
-    private MenuItem _miWrap;
     private TextView _textView;
     private Attribute _white;
 
@@ -99,7 +94,7 @@ public class SyntaxHighlighting : Scenario
     /// <typeparam name="T">The type of object to read from the file.</typeparam>
     /// <param name="filePath">The file path to read the object instance from.</param>
     /// <returns>Returns a new instance of the object read from the Json file.</returns>
-    public static T ReadFromJsonFile<T> (string filePath) where T : new()
+    public static T ReadFromJsonFile<T> (string filePath) where T : new ()
     {
         TextReader reader = null;
 
@@ -125,48 +120,28 @@ public class SyntaxHighlighting : Scenario
         Application.Init ();
 
         // Setup - Create a top-level application window and configure it.
-        Toplevel appWindow = new ();
+        Runnable appWindow = new ();
+
+        var menu = new MenuBar ();
+
+        MenuItem wrapMenuItem = CreateWordWrapMenuItem ();
+
+        menu.Add (
+                  new MenuBarItem (
+                                   "_TextView",
+                                   [
+                                       wrapMenuItem,
+                                       new Line (),
+                                       new MenuItem { Title = "_Syntax Highlighting", Action = ApplySyntaxHighlighting },
+                                       new Line (),
+                                       new MenuItem { Title = "_Load Text Cells", Action = ApplyLoadCells },
+                                       new MenuItem { Title = "_Save Text Cells", Action = SaveCells },
+                                       new Line (),
+                                       new MenuItem { Title = "_Quit", Action = Quit }
+                                   ]
+                                  )
+                 );
 
-        var menu = new MenuBar
-        {
-            Menus =
-            [
-                new (
-                     "_TextView",
-                     new []
-                     {
-                         _miWrap = new (
-                                        "_Word Wrap",
-                                        "",
-                                        () => WordWrap ()
-                                       )
-                         {
-                             CheckType = MenuItemCheckStyle
-                                 .Checked
-                         },
-                         null,
-                         new (
-                              "_Syntax Highlighting",
-                              "",
-                              () => ApplySyntaxHighlighting ()
-                             ),
-                         null,
-                         new (
-                              "_Load Rune Cells",
-                              "",
-                              () => ApplyLoadCells ()
-                             ),
-                         new (
-                              "_Save Rune Cells",
-                              "",
-                              () => SaveCells ()
-                             ),
-                         null,
-                         new ("_Quit", "", () => Quit ())
-                     }
-                    )
-            ]
-        };
         appWindow.Add (menu);
 
         _textView = new ()
@@ -192,6 +167,33 @@ public class SyntaxHighlighting : Scenario
         Application.Shutdown ();
     }
 
+    private MenuItem CreateWordWrapMenuItem ()
+    {
+        CheckBox checkBox = new ()
+        {
+            Title = "_Word Wrap",
+            CheckedState = _textView?.WordWrap == true ? CheckState.Checked : CheckState.UnChecked
+        };
+
+        checkBox.CheckedStateChanged += (s, e) =>
+                                        {
+                                            if (_textView is { })
+                                            {
+                                                _textView.WordWrap = checkBox.CheckedState == CheckState.Checked;
+                                            }
+                                        };
+
+        MenuItem item = new () { CommandView = checkBox };
+
+        item.Accepting += (s, e) =>
+                          {
+                              checkBox.AdvanceCheckState ();
+                              e.Handled = true;
+                          };
+
+        return item;
+    }
+
     /// <summary>
     ///     Writes the given object instance to a Json file.
     ///     <para>Object type must have a parameterless constructor.</para>
@@ -211,7 +213,7 @@ public class SyntaxHighlighting : Scenario
     ///     If false the file will be overwritten if it already exists. If true the contents will be appended
     ///     to the file.
     /// </param>
-    public static void WriteToJsonFile<T> (string filePath, T objectToWrite, bool append = false) where T : new()
+    public static void WriteToJsonFile<T> (string filePath, T objectToWrite, bool append = false) where T : new ()
     {
         TextWriter writer = null;
 
@@ -240,12 +242,9 @@ public class SyntaxHighlighting : Scenario
         {
             string csName = color.Key;
 
-            foreach (Rune rune in csName.EnumerateRunes ())
-            {
-                cells.Add (new () { Rune = rune, Attribute = color.Value.Normal });
-            }
+            cells.AddRange (Cell.ToCellList (csName, color.Value.Normal));
 
-            cells.Add (new () { Rune = (Rune)'\n', Attribute = color.Value.Focus });
+            cells.Add (new () { Grapheme = "\n", Attribute = color.Value.Focus });
         }
 
         if (File.Exists (_path))
@@ -266,10 +265,10 @@ public class SyntaxHighlighting : Scenario
     {
         ClearAllEvents ();
 
-        _green = new Attribute (Color.Green, Color.Black);
-        _blue = new Attribute (Color.Blue, Color.Black);
-        _magenta = new Attribute (Color.Magenta, Color.Black);
-        _white = new Attribute (Color.White, Color.Black);
+        _green = new (Color.Green, Color.Black);
+        _blue = new (Color.Blue, Color.Black);
+        _magenta = new (Color.Magenta, Color.Black);
+        _white = new (Color.White, Color.Black);
         _textView.SetScheme (new () { Focus = _white });
 
         _textView.Text =
@@ -290,7 +289,7 @@ public class SyntaxHighlighting : Scenario
         _textView.InheritsPreviousAttribute = false;
     }
 
-    private bool ContainsPosition (Match m, int pos) { return pos >= m.Index && pos < m.Index + m.Length; }
+    private bool ContainsPosition (Match m, int pos) => pos >= m.Index && pos < m.Index + m.Length;
 
     private void HighlightTextBasedOnKeywords ()
     {
@@ -388,12 +387,6 @@ public class SyntaxHighlighting : Scenario
         List<List<Cell>> cells = _textView.GetAllLines ();
         WriteToJsonFile (_path, cells);
     }
-
-    private void WordWrap ()
-    {
-        _miWrap.Checked = !_miWrap.Checked;
-        _textView.WordWrap = (bool)_miWrap.Checked;
-    }
 }
 
 public static class EventExtensions

部分文件因为文件数量过多而无法显示