Skip to content

NavigationView pane and list states become inconsistent when maximizing with an overlay pane open #11740

Description

@HazeMa0

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

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:

photos-bug1.mp4

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.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingneeds-triageIssue needs to be triaged by the area owners

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions