xaml-csharp-development-skill-for-avalonia

Menu Controls, ContextMenu, and MenuFlyout Patterns

Table of Contents

  1. Scope and APIs
  2. Choose the Right Menu Surface
  3. Top Menu Authoring (Menu + MenuItem)
  4. Command, HotKey, and InputGesture Wiring
  5. Stateful Menu Items (CheckBox and Radio)
  6. ContextMenu Placement and Lifecycle
  7. MenuFlyout and ContextFlyout Patterns
  8. Dynamic Menu Construction in C#
  9. Best Practices
  10. Troubleshooting

Scope and APIs

Primary APIs:

Important members:

Reference source files:

Choose the Right Menu Surface

Use Menu when:

Use ContextMenu when:

Use MenuFlyout when:

Top Menu Authoring (Menu + MenuItem)

XAML-first top menu with submenus:

<Menu xmlns="https://github.com/avaloniaui"
      xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <MenuItem Header="_File">
    <MenuItem Header="_Open"
              Command="{Binding OpenCommand}"
              InputGesture="Ctrl+O" />
    <MenuItem Header="_Save"
              Command="{Binding SaveCommand}"
              InputGesture="Ctrl+S" />
    <Separator />
    <MenuItem Header="E_xit"
              Command="{Binding ExitCommand}" />
  </MenuItem>

  <MenuItem Header="_Edit">
    <MenuItem Header="_Copy" Command="{Binding CopyCommand}" InputGesture="Ctrl+C" />
    <MenuItem Header="_Paste" Command="{Binding PasteCommand}" InputGesture="Ctrl+V" />
  </MenuItem>
</Menu>

Notes:

Command, HotKey, and InputGesture Wiring

InputGesture:

HotKey:

Common pattern:

<MenuItem Header="_Save"
          Command="{Binding SaveCommand}"
          HotKey="Ctrl+S"
          InputGesture="Ctrl+S" />

If you centralize shortcuts at view root:

<UserControl xmlns="https://github.com/avaloniaui"
             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
  <UserControl.KeyBindings>
    <KeyBinding Gesture="Ctrl+S" Command="{Binding SaveCommand}" />
  </UserControl.KeyBindings>
</UserControl>

Stateful Menu Items (CheckBox and Radio)

MenuItem supports toggled states:

<MenuItem xmlns="https://github.com/avaloniaui"
          Header="_View">
  <MenuItem Header="Show _Grid"
            ToggleType="CheckBox"
            IsChecked="{Binding ShowGrid}" />

  <Separator />

  <MenuItem Header="Zoom _100%"
            ToggleType="Radio"
            GroupName="Zoom"
            IsChecked="{Binding Zoom100}" />
  <MenuItem Header="Zoom _200%"
            ToggleType="Radio"
            GroupName="Zoom"
            IsChecked="{Binding Zoom200}" />
</MenuItem>

ContextMenu Placement and Lifecycle

Attached usage:

<Button xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Content="Item Actions">
  <Button.ContextMenu>
    <ContextMenu Placement="Pointer">
      <MenuItem Header="Rename" Command="{Binding RenameCommand}" />
      <MenuItem Header="Delete" Command="{Binding DeleteCommand}" />
    </ContextMenu>
  </Button.ContextMenu>
</Button>

Programmatic open with explicit target:

using Avalonia.Controls;

void ShowMenu(Control target, ContextMenu menu)
{
    if (!menu.IsOpen)
        menu.Open(target);
}

Lifecycle signals:

Use a menu flyout for context-style actions without directly attaching ContextMenu:

<Button xmlns="https://github.com/avaloniaui"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        Content="More">
  <Button.ContextFlyout>
    <MenuFlyout>
      <MenuItem Header="Refresh" Command="{Binding RefreshCommand}" />
      <MenuItem Header="Duplicate" Command="{Binding DuplicateCommand}" />
      <Separator />
      <MenuItem Header="Archive" Command="{Binding ArchiveCommand}" />
    </MenuFlyout>
  </Button.ContextFlyout>
</Button>

Key behaviors:

Dynamic Menu Construction in C#

using Avalonia.Controls;
using Avalonia.Input;

Menu BuildMainMenu(MainWindowViewModel vm)
{
    var file = new MenuItem { Header = "_File" };

    file.Items.Add(new MenuItem
    {
        Header = "_Open",
        Command = vm.OpenCommand,
        InputGesture = KeyGesture.Parse("Ctrl+O")
    });

    file.Items.Add(new MenuItem
    {
        Header = "_Save",
        Command = vm.SaveCommand,
        HotKey = KeyGesture.Parse("Ctrl+S"),
        InputGesture = KeyGesture.Parse("Ctrl+S")
    });

    file.Items.Add(new Separator());
    file.Items.Add(new MenuItem { Header = "E_xit", Command = vm.ExitCommand });

    return new Menu { Items = { file } };
}

Best Practices

Troubleshooting

  1. Menu item shows shortcut text but pressing keys does nothing.
    • InputGesture is display-only; register HotKey or a KeyBinding.
  2. Context menu opens on wrong target.
    • Ensure Open(control) uses an attached control and check PlacementTarget overrides.
  3. Radio menu items are not mutually exclusive.
    • Set ToggleType="Radio" and consistent GroupName values.
  4. Submenu remains open unexpectedly.
    • Check StaysOpenOnClick and command handlers that keep focus in popup.
  5. Shortcuts execute twice.
    • Remove duplicate KeyBinding/HotKey registrations across parent and child scopes.