microsoft / microsoft/microsoft-ui-xaml
NavigationView pane and list states become inconsistent when maximizing with an overlay pane open
- Dominant language
- C++
- Stars
- 8.4k
- Forks
- 942
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 105
Description
### Describe the bug
When a NavigationView is narrow enough to use Minimal display mode, opening its overlay pane and then maximizing the window can leave the pane, list-size visual state, and pane lifecycle events inconsistent.
Depending on the event ordering, I have observed the following outcomes:
1. The pane transitions normally.
2. The pane remains open after maximizing. Closing it with the toggle button leaves the navigation item labels visible beside the compact icons.
3. More rarely, maximizing immediately produces a compact-width pane whose item labels remain visible.
The issue does not require rapid clicking. Repeating the same resize sequence is sufficient to reproduce it.
### Why is this important?
NavigationView is commonly used as the main navigation surface of a desktop application. The bug leaves the control in a visibly invalid state and can also suppress a subsequent PaneClosing event.
I reproduced the behavior in WinUI Gallery and in a newly initialized, minimal WinUI 3 project. I have also observed the same visible behavior in the Windows Photos and Settings apps, although I cannot confirm that those applications reach exactly the same internal code path.
### Steps to reproduce the bug
1. Run the attached minimal reproduction project, or open WinUI Gallery.
2. Resize the window until NavigationView enters Minimal display mode.
3. Click the pane toggle button to open the overlay pane.
4. Maximize the window.
5. If the pane remains visually open, click the pane toggle button once to close it.
6. Observe that the pane can become compact while the navigation item label remain visible.
7. Repeat the sequence if necessary. The exact result is ordering-dependent, but no rapid interaction is required.
[demo.zip](https://github.com/user-attachments/files/31673454/demo.zip)
[log-annotated.log](https://github.com/user-attachments/files/31673457/log-annotated.log)
### Actual behavior
The logical pane state, SplitView visual state, and NavigationView list-size visual state can disagree.
In one ordering, the close completion is interpreted as an open completion, PaneClosed is not raised for the close, and a later PaneClosing event can be suppressed.
In another ordering, the pane ends in a compact closed state while NavigationView remains in ListSizeFull, leaving labels visible beside the compact icons.
### Expected behavior
After the adaptive layout change completes:
- an open pane must use the full list-size state;
- a closed pane in a compact SplitView mode must use ListSizeCompact;
- each committed close/open transition must produce the corresponding lifecycle completion without suppressing a later manual close.
### Screenshots
Demo:
https://github.com/user-attachments/assets/286c39f7-4a83-42a0-8aab-079c86385f46
https://github.com/user-attachments/assets/2d3c70d3-ef07-4a1a-ba1e-d9a939ede0ff
WinUI 3 Gallery:
https://github.com/user-attachments/assets/b0355129-67d7-4b7c-b21a-9e3b9cdbe548
Photos:
https://github.com/user-attachments/assets/efb58486-2487-4402-9c08-71f89fc2a264
### NuGet package version
Microsoft.WindowsAppSDK 2.4.0
### Windows version
Windows 11 (25H2): Build 26200, Windows Insider Build (xxxxx)
### Additional context
Similar historical symptoms were reported in #450 and #5474. I have not established that those reports have the same underlying cause.
Preliminary source analysis found two independent ordering problems:
1. `SplitView::OnDisplayModeStateChanged` handles an asynchronously delivered `CurrentStateChanged` event by reading the latest shared `m_isPaneOpeningOrClosing` and `IsPaneOpen` values. If a close is followed by an open before the queued close state notification is delivered, the close notification can be interpreted as an open completion. `PaneClosed` is then lost and `m_isPaneClosingByLightDismiss` can remain set. As a result, the next manual close can be mistaken for the completion of the earlier light-dismiss operation, suppressing its `PaneClosing` event.
2. `NavigationView::OnSplitViewPaneClosing` only enters `ListSizeCompact` when SplitView is already in a compact display mode. During the preparation phase of light-dismiss, `PaneClosing` can be delivered while the display mode is still `Overlay`, so we not change the list size. Adaptive layout can then change the mode to `CompactInline` while the pane remains open. During the deferred execution phase, the pane is finally closed, but `SplitView::OnPaneClosing` suppresses the second `PaneClosing` notification because the close is already marked as a light-dismiss operation. Consequently, neither phase changes the list from `ListSizeFull`, and no later callback reconciles it with the final compact closed state.
I have a proposed fix for both orderings and am willing to submit a PR.
Please assign the issue to me if appropriate.
Contributor guide
Research direction
Start with SplitView::OnDisplayModeStateChanged, NavigationView::OnSplitViewPaneClosing, and SplitView::OnPaneClosing, then reproduce the sequence using the attached minimal project or WinUI Gallery. Trace the event ordering during maximize and overlay close/open transitions. Done means the final pane and list-size states agree, and each committed transition raises the expected lifecycle event without suppressing a later manual close.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- desktop
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Active
- Clarity
- Mostly clear
- Newbie friendliness
- 45/100