Commit 7be132c
committed
* Ribbon MDI Fix
# Resolve #2921 – Double ribbon with MDI; caption/QAT hit-test misalignment
## Summary
Fixes [Issue #2921](#2921): when a `KryptonRibbon` is used on an MDI container (`KryptonForm` with `IsMdiContainer = true`), the following occurred:
1. **Double ribbon tabs** – Two identical rows of ribbon tabs (File, Tab) appeared, briefly when opening a maximized MDI child and sometimes persisting after closing all MDI children.
2. **Misaligned hit areas** – Close, minimize, and maximize buttons (and QAT) had their clickable areas shifted downward relative to the drawn buttons, so clicks did not register where the user clicked.
3. **Caption drag** – The area used for dragging the window (caption) did not align with the ribbon’s spare caption area.
This PR addresses all three by fixing coordinate usage for caption hit-testing and by re-syncing caption/ribbon state when the last MDI child is closed. It also adds a TestForm demo to reproduce and verify the scenario.
---
## Root cause
- **Hit-test mismatch:** `CustomCaptionArea` (set by the ribbon in **form client** coordinates) was hit-tested using **window** coordinates. The form uses `ScreenToWindow` for NC hit-test, so the point was in window space while the rectangle was in client space, causing the perceived downward shift for caption drag, close/min/max, and QAT.
- **Double tabs:** When the ribbon integrated into the form caption, context titles were in both the caption view and the ribbon view hierarchy; removing them from the caption area before injecting into the form (existing #2921 fix) avoids double layout/draw. When the last MDI child closed, caption/ribbon state was not refreshed, so double tabs could remain until a full re-layout.
---
## Changes
### Krypton.Toolkit
- **`KryptonForm.cs`**
- **`WindowChromeHitTest`:** Before testing `CustomCaptionArea.Contains(pt)`, convert the hit-test point from window coordinates to client coordinates using `RealWindowBorders`, so caption drag (and ribbon spare area) align with the drawn caption and buttons.
- **`WindowChromeHitTest`:** Use a single `Padding borders = RealWindowBorders` declaration for the method and remove the duplicate declaration that caused CS0136.
### Krypton.Ribbon
- **`ViewLayoutRibbonTabsArea.cs`**
- **`OnRibbonMdiChildActivate`:** When the active MDI child becomes `null` (last child closed) and the top-level form is a `KryptonForm`, call `_captionArea.PerformFormChromeCheck()`, `kryptonForm.RecreateMinMaxCloseButtons()`, `kryptonForm.PerformNeedPaint(true)`, and `kryptonForm.InvalidateNonClient()` so caption integration and layout are re-applied and double tabs do not persist.
*(Existing fix in `ViewDrawRibbonCaptionArea.cs` for #2921 – removing context titles from the caption area before injecting into the form – remains; it prevents the view from being in two hierarchies and thus avoids double layout/draw.)*
### TestForm (demo)
- **New: Ribbon MDI Demo (Issue #2921)**
- **`RibbonMdiDemo.cs`** – `KryptonForm` MDI container that creates a `KryptonRibbon` in `Load`, sets QAT above and `RibbonFileAppButton.AppButtonVisible`, adds File and Home tabs, and adds the ribbon as the first control (`Controls.Add` + `SetChildIndex(..., 0)`) for caption integration.
- **`RibbonMdiDemo.Designer.cs`** – Tool strip (Add Resizable Child, Add No-Resize Child, Open Maximized, Close All, Tile Horizontally/Vertically, Cascade) and status strip with verification text for #2921.
- **`RibbonMdiChildForm.cs`** – MDI child that can be resizable (`FormBorderStyle.Sizable`) or no-resize (`FixedSingle`), with short instructions for testing close/min/max and QAT alignment.
- **`StartScreen.cs`** – New button: “Ribbon MDI Demo (Issue #2921)” with description pointing to the issue and what to verify.
### Krypton.Utilities (unrelated build fix)
- **`Krypton.Utilities.csproj`**
- WebView2 `PackageReference` version range updated from `(1.0.0,2.0.0)` to `[1.0.0,2.0.0)` for an inclusive lower bound so restore resolves correctly (addresses NU1604/CS0234 when WebView2 was missing).
- For .NET 8+, `WEBVIEW2_AVAILABLE` is defined only when the file-based WebView2 SDK exists (`Exists('$(WebView2CoreDll)')`); otherwise the stub compiles and CS0234 is avoided.
- **`KryptonWebView2.cs`**
- Added an `#else` stub implementation of `KryptonWebView2` (inheriting `Control`) when `WEBVIEW2_AVAILABLE` is not defined, so the project builds when WebView2 is not present.
---
## How to verify
1. Run TestForm (e.g. `dotnet run --project "Source/Krypton Components/TestForm/TestForm.csproj" -c Debug -f net8.0-windows`).
2. Open **“Ribbon MDI Demo (Issue #2921)”** from the start screen.
3. Use **Open Maximized** (or **Add Resizable Child** then maximize) – confirm only one row of ribbon tabs (no double File/Tab).
4. Use **Close All** – confirm double tabs do not remain; single ribbon row only.
5. Use **Add No-Resize Child** (or resizable) – confirm close, minimize, and maximize buttons and QAT respond when clicking on the **drawn** buttons (no downward shift).
6. Drag the window by the caption area next to the ribbon – confirm it moves as expected.
---
## Checklist
- [x] Code builds (TestForm and affected projects).
- [x] Hit-test uses client coordinates for `CustomCaptionArea` so caption and buttons align.
- [x] Last MDI child close triggers caption re-check and invalidation to prevent persistent double tabs.
- [x] Ribbon MDI demo added and registered in StartScreen.
- [x] No new linter errors introduced in changed files.1 parent e68a4fb commit 7be132c
File tree
8 files changed
+403
-13
lines changed- Source/Krypton Components
- Krypton.Ribbon/View Layout
- Krypton.Toolkit/Controls Toolkit
- Krypton.Utilities
- Components/KryptonWebView2/Controls Toolkit
- TestForm
8 files changed
+403
-13
lines changedLines changed: 11 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1 | | - | |
| 1 | + | |
2 | 2 | | |
3 | 3 | | |
4 | 4 | | |
| |||
629 | 629 | | |
630 | 630 | | |
631 | 631 | | |
| 632 | + | |
| 633 | + | |
| 634 | + | |
| 635 | + | |
| 636 | + | |
| 637 | + | |
| 638 | + | |
| 639 | + | |
| 640 | + | |
| 641 | + | |
632 | 642 | | |
633 | 643 | | |
634 | 644 | | |
| |||
Lines changed: 10 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2031 | 2031 | | |
2032 | 2032 | | |
2033 | 2033 | | |
2034 | | - | |
| 2034 | + | |
| 2035 | + | |
| 2036 | + | |
| 2037 | + | |
| 2038 | + | |
2035 | 2039 | | |
2036 | | - | |
| 2040 | + | |
| 2041 | + | |
| 2042 | + | |
| 2043 | + | |
| 2044 | + | |
2037 | 2045 | | |
2038 | 2046 | | |
2039 | 2047 | | |
| |||
2067 | 2075 | | |
2068 | 2076 | | |
2069 | 2077 | | |
2070 | | - | |
2071 | 2078 | | |
2072 | 2079 | | |
2073 | 2080 | | |
| |||
Lines changed: 20 additions & 0 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
681 | 681 | | |
682 | 682 | | |
683 | 683 | | |
| 684 | + | |
| 685 | + | |
| 686 | + | |
| 687 | + | |
| 688 | + | |
| 689 | + | |
| 690 | + | |
| 691 | + | |
| 692 | + | |
| 693 | + | |
| 694 | + | |
| 695 | + | |
| 696 | + | |
| 697 | + | |
| 698 | + | |
| 699 | + | |
| 700 | + | |
| 701 | + | |
| 702 | + | |
| 703 | + | |
684 | 704 | | |
Lines changed: 8 additions & 9 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
62 | 62 | | |
63 | 63 | | |
64 | 64 | | |
65 | | - | |
| 65 | + | |
66 | 66 | | |
67 | | - | |
| 67 | + | |
68 | 68 | | |
69 | 69 | | |
70 | 70 | | |
| |||
81 | 81 | | |
82 | 82 | | |
83 | 83 | | |
84 | | - | |
| 84 | + | |
85 | 85 | | |
86 | | - | |
| 86 | + | |
87 | 87 | | |
88 | 88 | | |
89 | | - | |
90 | | - | |
| 89 | + | |
| 90 | + | |
91 | 91 | | |
92 | 92 | | |
93 | 93 | | |
94 | | - | |
95 | | - | |
96 | | - | |
| 94 | + | |
| 95 | + | |
97 | 96 | | |
98 | 97 | | |
99 | 98 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
| 26 | + | |
| 27 | + | |
| 28 | + | |
| 29 | + | |
| 30 | + | |
| 31 | + | |
| 32 | + | |
| 33 | + | |
| 34 | + | |
| 35 | + | |
| 36 | + | |
| 37 | + | |
| 38 | + | |
| 39 | + | |
| 40 | + | |
| 41 | + | |
| 42 | + | |
| 43 | + | |
| 44 | + | |
| 45 | + | |
| 46 | + | |
| 47 | + | |
| 48 | + | |
| 49 | + | |
| 50 | + | |
| 51 | + | |
| 52 | + | |
| 53 | + | |
| 54 | + | |
| 55 | + | |
| 56 | + | |
| 57 | + | |
| 58 | + | |
| 59 | + | |
| 60 | + | |
| 61 | + | |
| 62 | + | |
| 63 | + | |
| 64 | + | |
Lines changed: 179 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
0 commit comments