Primary APIs:
Menu, MenuItem, SeparatorContextMenuControl.ContextFlyout, FlyoutBase.ShowAttachedFlyoutICommand, MenuItem.InputGesture, MenuItem.IconReference docs:
24-html-css-buttons-links-toggle-and-split-command-surfaces.md53-menu-controls-contextmenu-and-menuflyout-patterns.md54-native-menu-and-native-menubar-integration.md| HTML/CSS idiom | Avalonia mapping |
|---|---|
top app menubar (<nav class="menubar">) |
Menu + top-level MenuItem |
nested dropdown (ul > li > ul) |
nested MenuItem hierarchy |
menu separator (<hr>) |
Separator |
| right-click context actions | ContextMenu on target control |
shortcut label (Ctrl+S) |
MenuItem InputGesture |
HTML/CSS:
<nav class="menubar">
<button>File</button>
<button>Edit</button>
<button>View</button>
</nav>
<Menu>
<MenuItem Header="_File" />
<MenuItem Header="_Edit" />
<MenuItem Header="_View" />
</Menu>
<ul class="menu">
<li>File
<ul>
<li>New</li>
<li>Open</li>
<li>Recent
<ul>
<li>project-a.sln</li>
<li>project-b.sln</li>
</ul>
</li>
</ul>
</li>
</ul>
<Menu>
<MenuItem Header="_File">
<MenuItem Header="New" Command="{CompiledBinding NewCommand}" />
<MenuItem Header="Open" Command="{CompiledBinding OpenCommand}" />
<Separator />
<MenuItem Header="Recent">
<MenuItem Header="project-a.sln" Command="{CompiledBinding OpenRecentACommand}" />
<MenuItem Header="project-b.sln" Command="{CompiledBinding OpenRecentBCommand}" />
</MenuItem>
</MenuItem>
</Menu>
HTML/CSS intent:
<div class="file-row" role="button">Report.csv</div>
.file-row {
user-select: none;
}
Avalonia:
<Border Padding="8" Background="#121821">
<TextBlock Text="Report.csv" />
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Open" Command="{CompiledBinding OpenFileCommand}" />
<MenuItem Header="Rename" Command="{CompiledBinding RenameFileCommand}" />
<Separator />
<MenuItem Header="Delete" Command="{CompiledBinding DeleteFileCommand}" />
</ContextMenu>
</Border.ContextMenu>
</Border>
<header class="workspace-header">
<nav class="menubar">...</nav>
</header>
<main>
<div class="file-row">Report.csv</div>
</main>
.workspace-header {
border-block-end: 1px solid #2a3240;
padding: 8px 12px;
}
<DockPanel>
<Menu DockPanel.Dock="Top">
<MenuItem Header="_File">
<MenuItem Header="New" Command="{CompiledBinding NewCommand}" InputGesture="Ctrl+N" />
<MenuItem Header="Open" Command="{CompiledBinding OpenCommand}" InputGesture="Ctrl+O" />
<MenuItem Header="Save" Command="{CompiledBinding SaveCommand}" InputGesture="Ctrl+S" />
<Separator />
<MenuItem Header="Exit" Command="{CompiledBinding ExitCommand}" />
</MenuItem>
<MenuItem Header="_Edit">
<MenuItem Header="Copy" Command="{CompiledBinding CopyCommand}" InputGesture="Ctrl+C" />
<MenuItem Header="Paste" Command="{CompiledBinding PasteCommand}" InputGesture="Ctrl+V" />
</MenuItem>
</Menu>
<StackPanel Margin="12" Spacing="6">
<Border Padding="8" Background="#121821">
<TextBlock Text="Report.csv" />
<Border.ContextMenu>
<ContextMenu>
<MenuItem Header="Open" Command="{CompiledBinding OpenFileCommand}" />
<MenuItem Header="Rename" Command="{CompiledBinding RenameFileCommand}" />
<Separator />
<MenuItem Header="Delete" Command="{CompiledBinding DeleteFileCommand}" />
</ContextMenu>
</Border.ContextMenu>
</Border>
</StackPanel>
</DockPanel>
using Avalonia.Controls;
using Avalonia.Input;
var menu = new Menu();
var file = new MenuItem { Header = "_File" };
file.Items.Add(new MenuItem { Header = "New", InputGesture = KeyGesture.Parse("Ctrl+N") });
file.Items.Add(new MenuItem { Header = "Open", InputGesture = KeyGesture.Parse("Ctrl+O") });
file.Items.Add(new MenuItem { Header = "Save", InputGesture = KeyGesture.Parse("Ctrl+S") });
file.Items.Add(new Separator());
file.Items.Add(new MenuItem { Header = "Exit" });
var edit = new MenuItem { Header = "_Edit" };
edit.Items.Add(new MenuItem { Header = "Copy", InputGesture = KeyGesture.Parse("Ctrl+C") });
edit.Items.Add(new MenuItem { Header = "Paste", InputGesture = KeyGesture.Parse("Ctrl+V") });
menu.Items.Add(file);
menu.Items.Add(edit);
var row = new Border
{
Padding = new Avalonia.Thickness(8),
Background = new Avalonia.Media.SolidColorBrush(Avalonia.Media.Color.Parse("#121821")),
Child = new TextBlock { Text = "Report.csv" }
};
row.ContextMenu = new ContextMenu();
row.ContextMenu.Items.Add(new MenuItem { Header = "Open" });
row.ContextMenu.Items.Add(new MenuItem { Header = "Rename" });
row.ContextMenu.Items.Add(new Separator());
row.ContextMenu.Items.Add(new MenuItem { Header = "Delete" });
var layout = new DockPanel();
DockPanel.SetDock(menu, Dock.Top);
layout.Children.Add(menu);
layout.Children.Add(new StackPanel { Margin = new Avalonia.Thickness(12), Children = { row } });
ICommand on VM) instead of reflection-based lookup.Dispatcher.UIThread if source data arrives asynchronously.InputGesture format and command binding target scope.ContextMenu.