Menus Deep Dive
Terminal.Gui provides a comprehensive, hierarchical menu system built on top of the Shortcut and Bar classes. This deep dive covers the architecture, class relationships, command routing, and interactions between the menu components.
Table of Contents
- Overview
- Class Hierarchy
- Component Descriptions
- Architecture
- Command Routing
- Interactions
- Usage Examples
- Keyboard Navigation
- Event Flow
Overview
The menu system in Terminal.Gui consists of the following key components:
| Component | Description |
|---|---|
| Shortcut | Base class for displaying a command, help text, and key binding |
| Bar | Container for Shortcut items, supports horizontal/vertical orientation |
| MenuItem | A Shortcut-derived item for use in menus, supports submenus |
| Menu | A vertically-oriented Bar that contains MenuItem items |
| MenuBarItem | A MenuItem that holds a PopoverMenu instead of a SubMenu |
| MenuBar | A horizontal Menu that contains MenuBarItem items |
| PopoverMenu | A Popover<Menu, MenuItem>-derived view that hosts cascading menus |
Class Hierarchy
The menu system builds upon a layered class hierarchy:
View
├── Shortcut // Command + HelpText + Key display
│ └── MenuItem // Menu-specific Shortcut with SubMenu support
│ └── MenuBarItem // MenuItem that uses PopoverMenu instead of SubMenu
│
├── Bar // Container for Shortcuts (horizontal/vertical)
│ └── Menu // Vertical Bar for MenuItems
│ └── MenuBar // Horizontal Menu for MenuBarItems
│
└── PopoverImpl // Base for popover views
└── Popover<TView, TResult> // Generic popover with content view + result extraction
└── PopoverMenu // Cascading menu popover (Popover<Menu, MenuItem>)
Inheritance Details
Shortcut → MenuItem → MenuBarItem:
- Shortcut displays command text, help text, and a key binding
- MenuItem extends Shortcut to add
SubMenusupport for nested menus - MenuBarItem extends MenuItem but replaces
SubMenuwith PopoverMenu
Bar → Menu → MenuBar:
- Bar is a generic container for Shortcut views with orientation support
- Menu is a vertical Bar specialized for MenuItem items
- MenuBar is a horizontal Menu specialized for MenuBarItem items
For completeness, here's how StatusBar fits in:
Bar → StatusBar:
Component Descriptions
Shortcut
Shortcut is the foundational building block. It displays three elements:
- CommandView - The command text (left side by default)
- HelpView - Help text (middle)
- KeyView - Key binding display (right side)
Shortcut shortcut = new ()
{
Title = "_Save", // CommandView text with hotkey
HelpText = "Save the file",
Key = Key.S.WithCtrl,
Action = () => SaveFile ()
};
IMPORTANT: The CommandView, HelpView, and KeyView are subviews of the shortcut. But how they are managed is an implementation detail and shortcut.SubViews should not be used to try to access them.
Key features:
- Supports
Actionfor direct invocation BindKeyToApplicationenables application-wide key bindingsAlignmentModescontrols element ordering (start-to-end or end-to-start)CommandViewcan be replaced with custom views (e.g., CheckBox)- Uses relay dispatch (
ConsumeDispatch=false): commands dispatched toCommandViewcomplete normally, then Shortcut is notified via a deferred callback - Sets CommandsToBubbleUp = [Activate, Accept]
Bar
Bar is a container that arranges Shortcut items either horizontally or vertically:
Bar statusBar = new ()
{
Orientation = Orientation.Horizontal,
Y = Pos.AnchorEnd ()
};
statusBar.Add (new Shortcut { Title = "_Help", Key = Key.F1 });
statusBar.Add (new Shortcut { Title = "_Quit", Key = Key.Q.WithCtrl });
Key features:
Orientationproperty controls layout directionAlignmentModesproperty controls item alignment- Supports mouse wheel navigation
- Auto-sizes based on content (DimAuto)
MenuItem
MenuItem extends Shortcut for use in menus:
MenuItem menuItem = new ()
{
Title = "_Open...",
HelpText = "Open a file",
Key = Key.O.WithCtrl,
Action = () => OpenFile ()
};
// Or bind to a command on a target view
MenuItem boundItem = new (myView, Command.Save);
Key features:
SubMenuproperty holds nested Menu for cascading menusTargetViewandCommandenable command binding to other views- Automatically gets focus on mouse enter
- Displays right-arrow glyph when it has a submenu
- When
SubMenuis set, aCommandBridgeconnects the SubMenu back to this MenuItem (bridging Activate and Accept commands across the non-containment boundary)
Menu
Menu is a vertical Bar specialized for menu items:
Menu fileMenu = new ([
new MenuItem ("_New", Key.N.WithCtrl, () => NewFile ()),
new MenuItem ("_Open...", Key.O.WithCtrl, () => OpenFile ()),
new Line (), // Separator
new MenuItem ("_Save", Key.S.WithCtrl, () => SaveFile ()),
new MenuItem ("Save _As...", () => SaveAs ())
]);
Key features:
- Vertical orientation by default
SuperMenuItemproperty links back to parent MenuItemSelectedMenuItemtracks current selection- Supports
Lineseparators between items - Uses
Schemes.Menucolor scheme by default - Sets CommandsToBubbleUp = [Accept, Activate] — enables command propagation up through the PopoverMenu hierarchy
- Overrides
OnActivatingto dispatch Activate to the focused MenuItem (manual dispatch, not theGetDispatchTargetpattern) ShowMenu()/HideMenu()control visibility and handle initialization;HideMenucascades to visible SubMenusGetAllSubMenus()performs depth-first traversal of the SubMenu hierarchyGetMenuItemsOfAllSubMenus()collects all MenuItems across the hierarchy, with optional predicateOnSelectedMenuItemChanged()handles SubMenu display: hides peer SubMenus, shows the selected item's SubMenu, and performs basic positioning
MenuBarItem
MenuBarItem extends MenuItem for use in MenuBar:
MenuBarItem fileMenuBarItem = new ("_File", [
new MenuItem ("_New", Key.N.WithCtrl, () => NewFile ()),
new MenuItem ("_Open...", Key.O.WithCtrl, () => OpenFile ()),
new Line (),
new MenuItem ("_Quit", Application.QuitKey, () => Application.RequestStop ())
]);
Important: MenuBarItem uses PopoverMenu instead of SubMenu. Attempting to set SubMenu will throw InvalidOperationException.
Key features:
PopoverMenuproperty holds the dropdown menu and setsTarget/Anchoron the popover for command bridging and positioningPopoverMenuOpendelegates toPopoverMenu.IsOpenand raisesPopoverMenuOpenChanged(relayed fromPopoverMenu.IsOpenChanged)- When
PopoverMenuis set, the basePopover<TView, TResult>.Targetproperty creates aCommandBridgeconnecting the PopoverMenu back to this MenuBarItem, bridging Activate commands across the non-containment boundary - Overrides
OnActivatingto togglePopoverMenuOpen, with a guard that ignoresBridgedcommands (which are notifications from PopoverMenu internals, not toggle requests) - Has a custom HotKey handler that skips SetFocus() before invoking Activate, preventing premature popover opening during MenuBarItem switching
MenuBar
MenuBar is a horizontal menu bar typically placed at the top of a window:
MenuBar menuBar = new ([
new MenuBarItem ("_File", [
new MenuItem ("_New", Key.N.WithCtrl, () => NewFile ()),
new MenuItem ("_Open...", Key.O.WithCtrl, () => OpenFile ()),
new Line (),
new MenuItem ("E_xit", Application.QuitKey, () => Application.RequestStop ())
]),
new MenuBarItem ("_Edit", [
new MenuItem ("_Cut", Key.X.WithCtrl, () => Cut ()),
new MenuItem ("_Copy", Key.C.WithCtrl, () => Copy ()),
new MenuItem ("_Paste", Key.V.WithCtrl, () => Paste ())
]),
new MenuBarItem ("_Help", [
new MenuItem ("_About...", () => ShowAbout ())
])
]);
// Add to window
window.Add (menuBar);
Key features:
Keyproperty defines the activation key (default:F9)Activeproperty controls whether the MenuBar is active — whenActivechanges, it drives CanFocus and hides any open PopoverMenus on deactivationIsOpen()returns whether any popover menu is visibleDefaultBorderStyleconfigurable via themes- Automatically positions at top with
Width = Dim.Fill () - Uses consume dispatch (
ConsumeDispatch=true,GetDispatchTarget => Focused) — the MenuBar owns activation state for its MenuBarItems - Blocks activation when
!Visible || !Enabled - Registers custom command handlers for HotKey,
Command.Quit,Command.Right, andCommand.Left
PopoverMenu
PopoverMenu extends Popover<Menu, MenuItem> and hosts cascading menus:
// Create a context menu
PopoverMenu contextMenu = new ([
new MenuItem (targetView, Command.Cut),
new MenuItem (targetView, Command.Copy),
new MenuItem (targetView, Command.Paste),
new Line (),
new MenuItem (targetView, Command.SelectAll)
]);
// Register with application (required!)
Application.Popover?.Register (contextMenu);
// Show at mouse position
contextMenu.MakeVisible ();
// Or show at specific position
contextMenu.MakeVisible (new Point (10, 5));
Key features:
- Inherits from
Popover<Menu, MenuItem>, which providesContentView,MakeVisible,SetPosition,Target,Anchor,Result, andResultExtractor Rootproperty aliasesContentViewand holds the top-level MenuKeyproperty for activation (default:Shift+F10)- MouseFlags property defines mouse button to show menu (default: right-click)
- Must be registered with
Application.Popoverbefore callingMakeVisible Target(inherited fromPopoverImpl) establishes aCommandBridgeso that commands from the menu hierarchy bridge to the target view- Auto-positions to ensure visibility on screen via overridden
SetPositionandGetAdjustedPosition - SubMenu show/hide is handled by
Menu.OnSelectedMenuItemChanged(); PopoverMenu's subscriber only adjusts positioning for screen boundaries viaGetMostVisibleLocationForSubMenu() - Registers custom command handlers for
Command.Right(enter submenu),Command.Left(leave submenu), andCommand.Quit(close menu)
Important: See the Popovers Deep Dive for complete details on popover lifecycle and requirements.
Architecture
Relationship Diagram
┌─────────────────────────────────────────────────────────────────────┐
│ Window │
│ ┌───────────────────────────────────────────────────────────────┐ │
│ │ MenuBar │ │
│ │ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │ │
│ │ │ MenuBarItem │ │ MenuBarItem │ │ MenuBarItem │ ... │ │
│ │ │ "File" │ │ "Edit" │ │ "Help" │ │ │
│ │ └──────┬──────┘ └─────────────┘ └─────────────┘ │ │
│ └─────────│─────────────────────────────────────────────────────┘ │
│ │ │
│ │ owns (+ CommandBridge) │
│ ▼ │
│ ┌──────────────────┐ │
│ │ PopoverMenu │ ◄─── Registered with Application.Popover │
│ │ ┌────────────┐ │ │
│ │ │ Menu │ │ ◄─── Root Menu │
│ │ │ (Root) │ │ │
│ │ │ ┌────────┐ │ │ │
│ │ │ │MenuItem│─┼──┼──► SubMenu ──► Menu ──► MenuItem ──► SubMenu │
│ │ │ │MenuItem│ │ │ ▲ (CommandBridge) │
│ │ │ │ Line │ │ │ │ │
│ │ │ │MenuItem│ │ │ Cascading │
│ │ │ └────────┘ │ │ Hierarchy │
│ │ └────────────┘ │ │
│ └──────────────────┘ │
└─────────────────────────────────────────────────────────────────────┘
Key Relationships
MenuBar contains MenuBarItems:
- MenuBar is a horizontal Menu containing MenuBarItem subviews
- Each MenuBarItem owns a PopoverMenu
MenuBarItem owns PopoverMenu (cross-boundary):
MenuBarItem.PopoverMenuproperty holds the dropdown- A
CommandBridgeconnects PopoverMenu back to MenuBarItem, bridging Activate commands PopoverMenuOpenChangedevent fires when visibility changes
PopoverMenu contains Root Menu (via ContentView):
PopoverMenu.RootaliasesPopover<Menu, MenuItem>.ContentView, which is the top-level Menu- A
CommandBridge(created by theContentViewsetter inPopover<TView, TResult>) bridges Activate from the Root Menu to the PopoverMenu - Menu self-manages SubMenu show/hide and basic positioning via
OnSelectedMenuItemChanged() - PopoverMenu adjusts positioning for screen boundaries and manages its own visibility lifecycle
Menu contains MenuItems:
Menu.SubViewscontains MenuItem instancesMenu.SelectedMenuItemtracks the focused itemMenu.CommandsToBubbleUp = [Command.Accept, Command.Activate]enables propagation
MenuItem may contain SubMenu (cross-boundary):
Command Routing
The menu system uses the Command Deep Dive infrastructure extensively. Understanding command routing is essential for working with menus.
Dispatch Patterns
Each menu component uses a specific command dispatch pattern:
| Component | GetDispatchTarget |
ConsumeDispatch |
Pattern |
|---|---|---|---|
| MenuBar | Focused (the focused MenuBarItem) |
true |
Consume: MenuBar owns activation state |
| Menu | Not overridden (manual dispatch in OnActivating) |
Not overridden | Dispatches Activate to focused MenuItem directly |
| MenuItem | Inherited from Shortcut (CommandView) |
false |
Relay: CommandView completes normally, then MenuItem is notified |
| MenuBarItem | Inherited from MenuItem/Shortcut | false |
Relay (inherited), plus custom OnActivating for PopoverMenu toggle |
CommandBridge (Cross-Boundary Routing)
The menu system has two non-containment boundaries that require CommandBridge:
MenuBarItem ↔ PopoverMenu: PopoverMenu is not a SubView of MenuBarItem — it is registered with
Application.Popoverand lives outside the view hierarchy. The bridge brings Activate events from the PopoverMenu back to the MenuBarItem so they can bubble up through the MenuBar.MenuItem ↔ SubMenu:
SubMenuis not a SubView of MenuItem — it is managed by the PopoverMenu's cascading infrastructure. The bridge brings Activate and Accept events from the SubMenu back to the MenuItem so they can bubble up through the Menu.
Routing Modes in Menu Context
| Mode | When It Occurs | Effect |
|---|---|---|
| Direct | User presses F9, or programmatic InvokeCommand |
MenuBar toggles Active on/off |
| BubblingUp | MenuBarItem activation bubbles to MenuBar | MenuBar identifies the source MenuBarItem and shows/hides its PopoverMenu |
| Bridged | MenuItem activation inside PopoverMenu bridges to MenuBarItem | MenuBarItem ignores the command (notification only — no PopoverMenu toggle) |
Command Bubbling
Menu sets CommandsToBubbleUp = [Accept, Activate]. This means:
- When a MenuItem fires Accept or Activate, the command bubbles up through the Menu to its SuperView
- For Root Menus inside a PopoverMenu, the command reaches the PopoverMenu
- The
CommandBridgeon MenuBarItem detects the Activate event on PopoverMenu and relays it to MenuBarItem - The MenuBarItem's activation then bubbles to the MenuBar via normal SuperView bubbling
Interactions
MenuBar Activation Flow
- User presses
F9(default) or clicks on MenuBar - MenuBar's HotKey handler fires — for direct activation, this calls InvokeCommand() (Activate)
MenuBar.OnActivatingruns:- If
!Visible || !Enabled: activation is blocked - If already
Active: toggles off (Active = false) - Otherwise: sets
Active = trueand callsShowItemon the first MenuBarItem with a PopoverMenu
- If
Active = truesets CanFocus =trueShowItemfocuses the MenuBarItem and setsPopoverMenuOpen = truePopoverMenuOpensetter callsPopoverMenu.MakeVisiblewith the calculated screen position
MenuBarItem HotKey Activation
When a MenuBarItem's HotKey (e.g., Alt+F for "_File") is pressed:
- The HotKey is processed on the MenuBarItem, which has a custom HotKey handler
- The handler skips SetFocus() (to prevent premature popover opening) and directly invokes Activate
MenuBarItem.OnActivatingtogglesPopoverMenuOpen- The activation bubbles up to
MenuBar.OnActivatingwithBubblingUprouting - MenuBar identifies the source MenuBarItem and either:
- Activates the MenuBar and shows the source item's PopoverMenu (if opening)
- Deactivates the MenuBar (if the PopoverMenu is closing)
Switching Between MenuBarItems
When the MenuBar is active and a PopoverMenu is open:
- Arrow keys:
Command.Right/Command.Leftadvance focus to the next/previous MenuBarItem. TheOnSelectedMenuItemChangedcallback detects the focus change and, while in popover browsing mode, callsShowItemon the newly focused item. - Mouse hover: Moving the mouse over a different MenuBarItem triggers
OnMouseEnter, which sets focus. If in browsing mode, the new item's PopoverMenu opens automatically. - HotKey: Pressing another MenuBarItem's HotKey directly invokes Activate on that item, causing a switch.
The _isSwitchingItem guard prevents premature deactivation during the brief interval when the old popover closes before the new one opens. The _popoverBrowsingMode flag tracks whether any popover is open, enabling auto-open behavior during navigation.
PopoverMenu Display Flow
MakeVisible()is called (optionally with a position) — inherited fromPopover<TView, TResult>Popover<TView, TResult>.SetPosition()calculates a visible location on screen (PopoverMenu overrides withnew SetPositionfor menu-specific positioning)Application.Popover.Show()is invoked, settingVisible = truePopoverMenu.OnVisibleChanged()runs — callsRoot.ShowMenu()(settingVisible = trueandEnabled = trueon the root Menu) beforebase.OnVisibleChanged()to ensure the Menu is enabled for focusPopover<TView, TResult>.OnVisibleChanged()syncsContentView.Visible- First MenuItem receives focus
Prerequisite: The PopoverMenu must be registered with Application.Popover before MakeVisible is called. For MenuBarItem, registration happens automatically in EndInit. For standalone context menus, call Application.Popover?.Register (contextMenu) explicitly.
Menu Selection Flow
- User navigates with arrow keys or mouse
Menu.Focusedchanges to new MenuItemMenu.OnSelectedMenuItemChanged()runs: hides peer SubMenus, shows selected item's SubMenu with basic positioningMenu.SelectedMenuItemChangedevent fires- When inside a PopoverMenu, the subscriber adjusts SubMenu positioning for screen boundaries
MenuItem Acceptance Flow
When a user presses Enter or clicks a MenuItem:
- Accept is invoked on the focused MenuItem
MenuItem.RaiseAcceptingfires the cancellable Accepting event- If not cancelled,
Shortcut.OnAcceptedruns:- If
TargetViewandCommandare set: invokes the command on the target view - If
Actionis set: invokes the action
- If
- Accepted fires on the MenuItem
- Because
Menu.CommandsToBubbleUpincludes Accept, the command bubbles up:- MenuItem → Menu → PopoverMenu
- PopoverMenu hides (closes) in response to the accepted command
- The
CommandBridgeon MenuBarItem brings the event into the containment hierarchy - MenuBar deactivates
Keyboard Navigation
| Key | Action |
|---|---|
F9 |
Toggle MenuBar activation |
Shift+F10 |
Show context PopoverMenu |
↑ / ↓ |
Navigate within Menu |
← / → |
Navigate MenuBar items / Expand-collapse submenus |
Enter |
Accept selected MenuItem |
Space |
Activate selected MenuItem (e.g., toggle a CheckBox CommandView) |
Escape / QuitKey |
Close menu / Deactivate MenuBar |
Hotkey (e.g., Alt+F) |
Activate/toggle specific MenuBarItem |
| Hotkey in Menu | Jump to MenuItem with matching hotkey |
Usage Examples
Basic MenuBar
using Terminal.Gui;
Application.Init ();
Window mainWindow = new () { Title = "Menu Demo" };
MenuBar menuBar = new ([
new MenuBarItem ("_File", [
new MenuItem ("_New", "", () => MessageBox.Query ("New", "Create new file?", "OK", "Cancel")),
new MenuItem ("_Open...", "", () => MessageBox.Query ("Open", "Open file dialog", "OK")),
new Line (),
new MenuItem ("E_xit", Application.QuitKey, () => Application.RequestStop ())
]),
new MenuBarItem ("_Edit", [
new MenuItem ("_Undo", Key.Z.WithCtrl, () => { }),
new Line (),
new MenuItem ("Cu_t", Key.X.WithCtrl, () => { }),
new MenuItem ("_Copy", Key.C.WithCtrl, () => { }),
new MenuItem ("_Paste", Key.V.WithCtrl, () => { })
])
]);
mainWindow.Add (menuBar);
Application.Run (mainWindow);
Application.Shutdown ();
Nested Submenus
MenuBarItem optionsMenu = new ("_Options", [
new MenuItem
{
Title = "_Preferences",
SubMenu = new Menu ([
new MenuItem { Title = "_General", Action = () => ShowGeneralPrefs () },
new MenuItem { Title = "_Editor", Action = () => ShowEditorPrefs () },
new MenuItem
{
Title = "_Advanced",
SubMenu = new Menu ([
new MenuItem { Title = "_Debug Mode", Action = () => ToggleDebug () },
new MenuItem { Title = "_Experimental", Action = () => ToggleExperimental () }
])
}
])
},
new Line (),
new MenuItem { Title = "_Reset to Defaults", Action = () => ResetDefaults () }
]);
Command Binding
// Bind menu items to commands on a target view
TextView editor = new () { X = 0, Y = 1, Width = Dim.Fill (), Height = Dim.Fill () };
MenuBar menuBar = new ([
new MenuBarItem ("_Edit", [
new MenuItem (editor, Command.Cut), // Uses editor's Cut command
new MenuItem (editor, Command.Copy), // Uses editor's Copy command
new MenuItem (editor, Command.Paste), // Uses editor's Paste command
new Line (),
new MenuItem (editor, Command.SelectAll)
])
]);
CheckBox in Menu
// Set CommandView.CanFocus = false to ensure the MenuItem receives activation for the CheckBox
CheckBox wordWrapCheckBox = new () { Title = "_Word Wrap", CanFocus = false };
wordWrapCheckBox.CheckedStateChanging += (_, e) =>
{
editor.WordWrap = e.NewValue == CheckState.Checked;
};
MenuBarItem viewMenu = new ("_View", [
new MenuItem { CommandView = wordWrapCheckBox },
new MenuItem
{
CommandView = new CheckBox { Title = "_Line Numbers" },
Key = Key.L.WithCtrl
}
]);
Context Menu (PopoverMenu)
PopoverMenu contextMenu = new ([
new MenuItem (editor, Command.Cut),
new MenuItem (editor, Command.Copy),
new MenuItem (editor, Command.Paste),
new Line (),
new MenuItem { Title = "_Properties...", Action = () => ShowProperties () }
]);
Application.Popover?.Register (contextMenu);
// Show on right-click
editor.MouseClick += (_, e) =>
{
if (e.Flags.HasFlag (MouseFlags.RightButtonClicked))
{
contextMenu.MakeVisible (e.ScreenPosition);
e.Handled = true;
}
};
Event Flow
Command Propagation Through the Menu Hierarchy
When a MenuItem is activated or accepted, commands propagate through the hierarchy using two mechanisms: command bubbling (within the containment hierarchy) and CommandBridge (across non-containment boundaries).
Accept Flow (e.g., user presses Enter on a MenuItem)
MenuItem
├─ Accepting event (cancellable)
├─ Accepted event
↓ (bubbles via CommandsToBubbleUp)
Menu (Root)
├─ Accepting event
├─ Accepted event
↓ (PopoverMenu receives via containment)
PopoverMenu
├─ Closes (Visible = false)
↓ (CommandBridge bridges to MenuBarItem)
MenuBarItem
├─ PopoverMenuOpen = false (via VisibleChanged)
↓ (bubbles to SuperView)
MenuBar
├─ Active = false
└─ Deactivates
Activate Flow (e.g., user presses Space to toggle a CheckBox in a MenuItem)
MenuItem's CommandView (e.g., CheckBox)
├─ Activating / Activated events
↓ (relay dispatch from Shortcut)
MenuItem
├─ Activating / Activated events
↓ (bubbles via CommandsToBubbleUp)
Menu (Root / ContentView)
├─ Activated event
↓ (ContentView CommandBridge bridges to PopoverMenu)
PopoverMenu
├─ OnActivating hides popover for non-HotKey bridged commands
├─ Activated event
↓ (Target CommandBridge bridges to MenuBarItem)
MenuBarItem
├─ OnActivating sees Bridged routing → ignores (no toggle)
↓ (bubbles to SuperView)
MenuBar
├─ OnActivating sees BubblingUp routing → notification only
Selection Change Events
User navigates → Menu.Focused changes
↓
Menu.OnFocusedChanged ()
↓
SelectedMenuItem updated
↓
Menu.OnSelectedMenuItemChanged ()
├─ Hides peer SubMenus
├─ Shows selected SubMenu (with basic positioning)
↓
SelectedMenuItemChanged event
↓
PopoverMenu adjusts SubMenu positioning (screen boundaries)
Key Event Processing
Key events are processed depth-first through the view hierarchy:
NewKeyDownEvent (key)
├─ If has Focused SubView → recurse into Focused
├─ RaiseKeyDown (key) — OnKeyDown + KeyDown event
├─ InvokeCommandsBoundToKey (key) — KeyBindings lookup
├─ InvokeCommandsBoundToHotKey (key) — HotKeyBindings (this + SubViews)
└─ RaiseKeyDownNotHandled (key) — OnKeyDownNotHandled + event
For menus specifically:
- MenuBar binds
F9to HotKey (viaHotKeyBindings) - MenuBar binds
F9andApplication.QuitKeytoCommand.Quit(viaKeyBindings) - MenuBar binds arrow keys to
Command.Right/Command.Left - PopoverMenu binds arrow keys to
Command.Right/Command.Leftfor submenu navigation - PopoverMenu binds
Escape/QuitKeytoCommand.Quit
Configuration
Menu appearance can be customized via themes:
// Set default border style for menus
Menu.DefaultBorderStyle = LineStyle.Single;
// Set default border style for menu bars
MenuBar.DefaultBorderStyle = LineStyle.None;
// Set default activation key for menu bars
MenuBar.DefaultKey = Key.F10;
// Set default activation key for popover menus
PopoverMenu.DefaultKey = Key.F10.WithShift;
These can also be configured in config.json:
{
"Themes": {
"Default": {
"Menu.DefaultBorderStyle": "Single",
"MenuBar.DefaultBorderStyle": "None"
}
},
"Settings": {
"MenuBar.DefaultKey": "F9",
"PopoverMenu.DefaultKey": "Shift+F10"
}
}
See Also
- Popovers Deep Dive - Complete details on popover lifecycle
- Command Deep Dive - Command binding, dispatch, and routing
- Keyboard Deep Dive - Key binding system
- Events Deep Dive - Event handling patterns
- MenuBar API Reference
- PopoverMenu API Reference
- MenuItem API Reference