fix(NavMenu): ignore stale selected nodes after item replacement

This commit is contained in:
chinboy
2026-08-07 09:16:23 +08:00
parent 6c2ad58df9
commit 54c6b52069
2 changed files with 77 additions and 1 deletions
@@ -118,7 +118,29 @@ internal sealed class NavMenuSelectionCoordinator
}
var selectedNode = _appliedSelectedNode ?? menu.SelectedItem;
return selectedNode is null ? null : menu.FindRealizedMenuItem(selectedNode);
if (selectedNode is null)
{
return null;
}
if (!BelongsToMenu(menu, selectedNode))
{
Reset();
return null;
}
return menu.FindRealizedMenuItem(selectedNode);
}
private static bool BelongsToMenu(NavMenu menu, INavMenuNode node)
{
var rootNode = node;
while (rootNode.ParentNode is INavMenuNode parentNode)
{
rootNode = parentNode;
}
return NavMenuEntryGraph.ContainsDirectNode(menu.Items, rootNode);
}
private void Reset()
@@ -302,6 +302,60 @@ public class NavMenuSelectionTests
}
}
[Fact]
public void NavMenu_Selects_New_Item_After_Replacing_The_Selected_Item_Tree()
{
var first = new NavMenuNode
{
Header = "First",
ItemKey = "first"
};
var replacement = new NavMenuNode
{
Header = "Replacement",
ItemKey = "replacement"
};
var menu = new AtomUI.Desktop.Controls.NavMenu
{
Mode = NavMenuMode.Inline,
IsMotionEnabled = false
};
menu.Items.Add(first);
var window = new Avalonia.Controls.Window
{
Width = 320,
Height = 240,
Content = menu
};
try
{
window.Show();
Dispatcher.UIThread.RunJobs();
var firstContainer = menu.ContainerFromItem(first).ShouldBeOfType<NavMenuItem>();
menu.InteractionHandler.ShouldNotBeNull();
menu.InteractionHandler.Select(firstContainer);
menu.Items.Clear();
menu.Items.Add(replacement);
Dispatcher.UIThread.RunJobs();
var replacementContainer = menu.ContainerFromItem(replacement).ShouldBeOfType<NavMenuItem>();
var replacementHeader = GetItemHeader(replacementContainer);
Should.NotThrow(() => MouseDown(replacementHeader, window));
Dispatcher.UIThread.RunJobs();
replacementContainer.IsSelected.ShouldBeTrue();
menu.SelectedItem.ShouldBeSameAs(replacement);
}
finally
{
window.Close();
}
}
[Fact]
public void NavMenu_Detach_Then_Programmatic_Sibling_Selection_Clears_Previous_Selection()
{