microsoft / microsoft/microsoft-ui-xaml
NavigationView: Moving selected item between groups leaves IsChildSelected=true on former ancestors
Nobody has claimed this yet.
- Dominant language
- C++
- Stars
- 8.4k
- Forks
- 942
- Avg merge
- 2d 7h
- Merged PRs (30d)
- 105
Description
### Describe the bug
When using a hierarchical `NavigationView`, moving a currently selected item from one parent item/group to another leaves `IsChildSelected` set to `true` on its former ancestors.
As a result:
- Collapsing an unrelated former parent moves the selection indicator to that group, even though `SelectedItem` still points to the original leaf in its new location.
- Inserting a root item before the ancestor and selecting a top-level item can also leave the original parent marked as child-selected.
### Why is this important?
In apps where items are dynamically categorized into hierarchical groups (e.g. grouping active/pending tasks, chat sessions, or folders), reparenting the currently selected item corrupts the ancestor selection visual states. When the user collapses the former group, it mistakenly claims the active selection indicator, misleading the user about which item is selected.
### Steps to reproduce the bug
1. Bind a left hierarchical `NavigationView` with two parent groups (e.g., Group A and Group B) containing child items in `ObservableCollection`.
2. Expand both Group A and Group B.
3. Select a child item under Group A (`SelectedItem = child1`). Notice Group A has `IsChildSelected = true`.
4. Move `child1` from Group A's child collection to Group B's child collection, and ensure `SelectedItem` is `child1`.
5. Observe that Group A's container still has `IsChildSelected = true`.
6. Collapse Group A.
7. Observe that Group A's selection indicator becomes active, incorrectly displaying the selection indicator on Group A while `SelectedItem` remains `child1` under Group B.
### Actual behavior
Former ancestor containers retain `IsChildSelected = true` after the selected child item is reparented to another group. Collapsing the former parent displays a phantom selection indicator on that container.
### Expected behavior
Former ancestors should have `IsChildSelected` cleared when their selected descendant is reparented or no longer under that ancestor. Only current active ancestors of `SelectedItem` should report `IsChildSelected = true`.
### Screenshots
_No response_
### NuGet package version
Microsoft.WindowsAppSDK 1.6+ (reproduced on Windows App SDK 2.4.0 / .NET 10 standalone native app)
### Windows version
Windows 11 (24H2): Build 26100, Windows 11 (23H2): Build 22631
### Additional context
In `controls/dev/NavigationView/NavigationView.cpp#L2494-L2511` (`OnSelectionModelSelectionChanged`):
Ancestor unselection and cleanup resolves through the cached index path (`m_lastSelectedItemIndexPath`), which does not accurately track ancestor state changes when the item collection/hierarchy mutates or when items are moved between containers.
Cross-reference:
- Uno Platform issue: https://github.com/unoplatform/uno/issues/24508
- Uno Platform PR: https://github.com/unoplatform/uno/pull/24509
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in controls/dev/NavigationView/NavigationView.cpp at OnSelectionModelSelectionChanged, especially lines 2494-2511, and trace how m_lastSelectedItemIndexPath handles ancestor cleanup. Reproduce moving a selected child between groups, then verify that former ancestors clear IsChildSelected while only the current ancestors retain it.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- cpp
- Domain
- desktop, frontend
- Issue type
- Bug
- Difficulty
- 3/5
- Estimated time
- 1-2 days
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 76/100