Skip to content

Menu

Menu is a trigger-anchored dropdown built entirely on native WPF menu controls (a ToggleButton trigger, a ContextMenu popup, MenuItem-derived items), so roving focus, typeahead, mnemonics, and submenu opening/closing are inherited rather than reimplemented. The web contract’s 17-part anatomy (Root/Trigger/Portal/Positioner/Popup/Arrow/Item/CheckboxItem/ItemIndicator/Group/ GroupLabel/RadioGroup/RadioItem/Separator/Sub/SubTrigger/SubContent) collapses onto 8 WPF classes, with submenus expressed as ordinary native MenuItem nesting.

xmlns:menu="clr-namespace:Navius.Wpf.Primitives.Controls.Menus;assembly=Navius.Wpf.Primitives"
<StackPanel>
<StackPanel.Resources>
<menu:NaviusMenuPopup x:Key="FileMenu">
<menu:NaviusMenuItem Header="New" Command="ApplicationCommands.New" />
<menu:NaviusMenuCheckboxItem Header="Word wrap" Checked="{Binding WordWrap, Mode=TwoWay}" />
<menu:NaviusMenuSeparator />
<menu:NaviusMenuItem Header="Recent">
<menu:NaviusMenuItem Header="Document 1.txt" />
</menu:NaviusMenuItem>
</menu:NaviusMenuPopup>
</StackPanel.Resources>
<menu:NaviusMenuTrigger Content="File" Menu="{StaticResource FileMenu}" />
</StackPanel>

A NaviusMenuItem with child NaviusMenuItems automatically becomes a submenu header; there is no separate Sub/SubTrigger/SubContent type.

Property Type Default From Description
Menu NaviusMenuPopup? null NaviusMenuTrigger The popup this trigger opens and closes.
IsChecked bool? false ToggleButton Doubles as the contract’s data-popup-open; toggling opens/closes Menu with itself as PlacementTarget. The popup’s own Closed event resets it back to false for every dismissal path.
Side PlacementSide Bottom NaviusMenuPopup Placement side; combined with Align via a CustomPopupPlacementCallback (native PlacementMode has no side+align axis).
Align PlacementAlign Center NaviusMenuPopup Placement alignment.
SideOffset double 0 NaviusMenuPopup -
AlignOffset double 0 NaviusMenuPopup -
Loop bool false NaviusMenuPopup Kept for parameter-surface parity; native MenuItem/ContextMenu arrow-key navigation has no wrap-around switch, so it has no behavioral effect.
TextValue string? null NaviusMenuItemBase Overrides the text typeahead matches against; writes straight onto native TextSearch.Text.
Checked bool? false NaviusMenuCheckboxItem Tri-state API surface (null = indeterminate); registers a default of false, not null (see Web deltas). Mirrored into native IsChecked (indeterminate maps to false).
IsIndeterminate bool false NaviusMenuCheckboxItem Drives the dash glyph; set from Checked == null.
Value string "" NaviusMenuRadioItem This item’s value within its group.
GroupName string "" NaviusMenuRadioItem Items sharing GroupName under the same owning menu/submenu are mutually exclusive; not WPF’s attached RadioButton.GroupName.
Content object - ContentControl NaviusMenuGroupLabel’s heading text; non-focusable, safely skipped by native item roving like Separator is.
Event Signature Fires when
Select RoutedEventHandler An item, checkbox item, or radio item is activated (click or Enter/Space); cancelable, PreventDefault() keeps the menu open instead of closing it.
CheckedChanged RoutedEventHandler NaviusMenuCheckboxItem.Checked toggles, from the DP-change callback so it fires on every change, programmatic or click-driven.
Key Behavior
ArrowDown / ArrowUp (open menu) Native roving focus between enabled MenuItem siblings (inherited, not reimplemented).
Home Native roving to the first enabled item (inherited).
A printable character Native first-letter typeahead via TextSearch.Text (inherited).
ArrowRight (ArrowLeft in rtl) / Enter / Space (on a submenu header) Opens the submenu (native MenuItem.Role == SubmenuHeader handling).
ArrowLeft (ArrowRight in rtl) (inside a submenu) Closes only that submenu (native).
Enter / Space (on Item / CheckboxItem / RadioItem) Activates the item: raises Select, then closes the owning ContextMenu unless PreventDefault() was called.
Escape Closes the open ContextMenu (native Popup dismissal).

NaviusMenuPopup ships no custom automation peer; it inherits the native ContextMenu automation peer. NaviusMenuItem/NaviusMenuCheckboxItem/NaviusMenuRadioItem inherit MenuItemAutomationPeer (AutomationControlType.MenuItem); when IsCheckable is true the peer implements IToggleProvider, exercised by the unit suite’s MenuItemAutomationPeer IToggleProvider/ToggleState test. No custom peer was added anywhere in this family.

  • 17 web parts collapse onto 8 WPF classes. NaviusMenuPortal is a no-op (WPF popups already float in their own window layer); NaviusMenuPositioner folds onto Side/Align/SideOffset/ AlignOffset on NaviusMenuPopup directly.
  • NaviusMenuArrow is not implemented (deferred).
  • NaviusMenuGroup and NaviusMenuRadioGroup have no wrapper type: a transparent non-MenuItem wrapper would break native MenuItem/ContextMenu arrow-key roving, which only navigates MenuItem-typed containers. Grouping is visual-only (NaviusMenuGroupLabel plus item ordering); radio mutual exclusion is a GroupName property scoped to the item’s immediate owning menu/submenu, not a wrapping element.
  • NaviusMenuSub/SubTrigger/SubContent collapse into native MenuItem submenu nesting.
  • The dismiss-hook superset (OnOpenAutoFocus/OnCloseAutoFocus/OnEscapeKeyDown/ OnPointerDownOutside/OnFocusOutside/OnInteractOutside) is not implemented: native ContextMenu/Popup already dismiss on outside-click and Escape.
  • Modal is not implemented (no scroll-lock equivalent).
  • Side/Align cover the contract’s 4-side x 3-align matrix through a CustomPopupPlacementCallback with flip/shift disabled, so placement is a single fixed choice, not collision-aware like the web positioner.
  • Loop has no behavioral effect: native MenuItem/ContextMenu arrow-key navigation has no public wrap-around switch.
  • Known residual (M6 audit): NaviusMenuCheckboxItem.Checked registers a default of false, not null (indeterminate) as the web contract specifies. A default-constructed checkbox item starts unchecked rather than indeterminate, and the dash glyph (driven by the separate IsIndeterminate flag, itself defaulting false) does not show until Checked is explicitly set. Low impact since indeterminate is reachable only programmatically in the web contract too.
  • Namespace note: the folder is Controls/Menu/, but the C# namespace is Navius.Wpf.Primitives.Controls.Menus (plural), to avoid a naming collision with the sibling Menubar family’s own use of bare Menu.

The Menu Gallery page rendered at the pinned commit, in each theme.

Menu Gallery page in the light theme

Menu Gallery page in the dark theme

Menu Gallery page in the high contrast theme