This document captures the design and implementation details of MenuBar.
For end-user usage and examples, see MenuBar.
MenuBar control (top-level bar)MenuItem model (menu tree)Popup)Command.CanExecuteFor(...) and Command.IsVisibleFor(...) when a menu item is backed by a Command.Command.Gesture / Command.Sequence when not explicitly provided.CellBuffer and use simple layout).MenuBar is a Visual with:
Items : BindableList<MenuItem> (bindable getter) - top-level menu items.Notes:
MenuBar is focusable and defaults to HorizontalAlignment = Align.Stretch.Popup windows, so this control is intended for fullscreen apps.MenuItem is the menu node model and implements IVisualElement:
Header : Visual - required header visual (often a TextBlock).Items : BindableList<MenuItem> (bindable getter) - submenu items.Command : Command? (bindable) - optional backing command.CommandTarget : Visual? - optional explicit target used for command visibility/enabled and execution.Action : Delegator<Action> (bindable) - optional action used when Command is null.Icon : Visual? (bindable) - optional icon visual.Shortcut : Visual? (bindable) - optional shortcut visual (overrides derived shortcut).IsSeparator : bool (bindable) - separator row flag.IsVisible : bool (bindable) - visibility flag (combined with Command.IsVisibleFor).IsEnabled : bool (bindable) - enabled flag (combined with Command.CanExecuteFor).Helpers:
MenuItem.Separator() / MenuItem.CreateSeparator() creates a disabled separator item.When the menu is opened, items are filtered by visibility:
MenuItem.IsVisible must be true.MenuItem.Command is set, it must also be visible for the effective target (CommandTarget ?? menuTarget).Enabled state for selection and invocation:
MenuItem.IsEnabled must be true.MenuItem.Command is set, it must also be executable for the effective target.The menu target is resolved as:
TerminalApp.FocusedElement ?? TerminalApp.Root (when available), otherwise the MenuBar itself.When a selectable item is activated:
Command is set, the menu invokes Command.Execute(effectiveTarget) (after re-checking visibility and enabled state).Action.Invoke (if any).After invocation, all menus are closed.
MenuBar lays out top-level items horizontally:
MenuBarStyle.Padding applies around the bar.MenuBarStyle.ItemSpacing applies between items.MenuBarItem that applies MenuBarStyle.ItemPadding around the header.Opening a menu creates an internal MenuList visual hosted inside a Popup:
Below the active top-level MenuBarItem.Right of the active menu row.PopupStyle.Default with { Padding = Thickness.Zero }).MenuListStyle.PopupTemplateFactory can wrap the list (the default uses a Group wrapper to provide chrome).Menu list sizing:
Padding.Vertical + itemCount (each row is 1 cell high).Padding.Horizontal + maxRowWidth + submenuColumnWidth.
submenuColumnWidth is 0 when there are no visible submenus.MenuBar.RenderOverride fills its bounds with spaces using MenuBarStyle.ResolveBarStyle(theme).
Each MenuBarItem fills its own bounds with spaces using MenuBarStyle.ResolveItemStyle(...) based on:
MenuList.RenderOverride renders row backgrounds and indicators:
MenuListStyle.ResolveSeparatorStyle(...) for separators, orMenuListStyle.ResolveItemStyle(...) for normal rows (enabled/selected/hovered).theme.Lines.Horizontal.Rendering is simple: there is no clipping or virtualization; the list is sized to its content.
When the menu bar has focus:
When a menu list has focus:
Menus are hosted in popups. While a menu popup is open, global commands should not execute "behind" the popup. This is covered by tests (see below).
MenuBar uses:
MenuBarStyle (src/XenoAtom.Terminal.UI/Styling/MenuBarStyle.cs):
MenuListStyle (src/XenoAtom.Terminal.UI/Styling/MenuListStyle.cs):
PopupTemplateFactory)Tests:
src/XenoAtom.Terminal.UI.Tests/MenuTests.cs (open/invoke, submenu navigation, popup close, global command blocking)Demo:
samples/ControlsDemo/Demos/MenuBarDemo.csUser documentation:
site/docs/controls/menubar.mdMenuBar commands for discoverability (e.g. open menu, close menu, next/previous top-level).MenuBarStyle (where applicable).src/XenoAtom.Terminal.UI.Tests.