Add support for filterable, nested context menus (#38776)
Some checks are pending
Spell checking / Check Spelling (push) Waiting to run
Spell checking / Report (Push) (push) Blocked by required conditions
Spell checking / Report (PR) (push) Blocked by required conditions
Spell checking / Update PR (push) Waiting to run

_targets #38573_

At first I just wanted to add support for nested context menus.

But then I also had to add a search box, so the focus wouldn't get weird.

End result:

![nested-menus-001](https://github.com/user-attachments/assets/4e8f1ec8-4b09-4095-9b81-caf7abde8aea)

This gets rid of the need to have the search box and the command bar both track item keybindings - now it's just in the command bar.

Closes #38299
Closes #38442
This commit is contained in:
Mike Griese
2025-04-24 13:32:07 -05:00
committed by GitHub
parent 195ff24a85
commit f63fcfd91c
15 changed files with 607 additions and 170 deletions

View File

@@ -48,7 +48,7 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
public List<CommandContextItemViewModel> MoreCommands { get; private set; } = [];
IEnumerable<CommandContextItemViewModel> ICommandBarContext.MoreCommands => MoreCommands;
IEnumerable<CommandContextItemViewModel> IContextMenuContext.MoreCommands => MoreCommands;
public bool HasMoreCommands => MoreCommands.Count > 0;
@@ -187,23 +187,26 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
// use Initialize straight up
MoreCommands.ForEach(contextItem =>
{
contextItem.InitializeProperties();
contextItem.SlowInitializeProperties();
});
_defaultCommandContextItem = new(new CommandContextItem(model.Command!), PageContext)
if (!string.IsNullOrEmpty(model.Command.Name))
{
_itemTitle = Name,
Subtitle = Subtitle,
Command = Command,
_defaultCommandContextItem = new(new CommandContextItem(model.Command!), PageContext)
{
_itemTitle = Name,
Subtitle = Subtitle,
Command = Command,
// TODO this probably should just be a CommandContextItemViewModel(CommandItemViewModel) ctor, or a copy ctor or whatever
};
// TODO this probably should just be a CommandContextItemViewModel(CommandItemViewModel) ctor, or a copy ctor or whatever
};
// Only set the icon on the context item for us if our command didn't
// have its own icon
if (!Command.HasIcon)
{
_defaultCommandContextItem._listItemIcon = _listItemIcon;
// Only set the icon on the context item for us if our command didn't
// have its own icon
if (!Command.HasIcon)
{
_defaultCommandContextItem._listItemIcon = _listItemIcon;
}
}
Initialized |= InitializedState.SelectionInitialized;
@@ -398,23 +401,6 @@ public partial class CommandItemViewModel : ExtensionObjectViewModel, ICommandBa
base.SafeCleanup();
Initialized |= InitializedState.CleanedUp;
}
/// <summary>
/// Generates a mapping of key -> command item for this particular item's
/// MoreCommands. (This won't include the primary Command, but it will
/// include the secondary one). This map can be used to quickly check if a
/// shortcut key was pressed
/// </summary>
/// <returns>a dictionary of KeyChord -> Context commands, for all commands
/// that have a shortcut key set.</returns>
internal Dictionary<KeyChord, CommandContextItemViewModel> Keybindings()
{
return MoreCommands
.Where(c => c.HasRequestedShortcut)
.ToDictionary(
c => c.RequestedShortcut ?? new KeyChord(0, 0, 0),
c => c);
}
}
[Flags]