Using your own Context Menu
Karolina builds ERP software for the Polish manufacturing sector. Her flagship product is a WPF accounts-and-invoicing suite, and one of its screens is a free-form notes editor that accountants use to annotate invoices, attach context for auditors, and flag confidential entries. The accountants asked her for a right-click menu that matched the way they worked -- not the editor's standard cut, copy, paste menu.
What they wanted was a menu with their domain commands at the top: "Insert Invoice Reference", "Insert Customer Number", "Mark as Confidential", and a separator before the usual clipboard items. Karolina was not looking forward to ripping out the editor's context menu and rebuilding everything from scratch.
She did not have to. The WpfHtmlEditor exposes a property called EditorContextMenuStrip that takes a standard WPF ContextMenu and uses it in place of the built-in one. The name keeps the "Strip" suffix from the original WinForms editor so source code that targets both platforms compiles unchanged; the WPF type is the regular System.Windows.Controls.ContextMenu, not the WinForms ContextMenuStrip.
She built the menu in XAML so her designer could style it with the same look as the rest of the application:
<Window xmlns:editor="clr-namespace:SpiceLogic.HtmlEditor.WPF;
assembly=SpiceLogic.HtmlEditor.WPF">
<Window.Resources>
<ContextMenu x:Key="AccountantMenu">
<MenuItem Header="Insert Invoice Reference" Click="OnInsertInvoiceRef" />
<MenuItem Header="Insert Customer Number" Click="OnInsertCustomerId" />
<MenuItem Header="Mark as Confidential" Click="OnMarkConfidential" />
<Separator />
<MenuItem Header="Cut" Command="ApplicationCommands.Cut" />
<MenuItem Header="Copy" Command="ApplicationCommands.Copy" />
<MenuItem Header="Paste" Command="ApplicationCommands.Paste" />
</ContextMenu>
</Window.Resources>
<editor:WpfHtmlEditor x:Name="editor"
EditorContextMenuStrip="{StaticResource AccountantMenu}" />
</Window>For the team members who preferred code-behind, the same assignment worked in C#:
var menu = new ContextMenu();
menu.Items.Add(new MenuItem { Header = "Insert Invoice Reference" });
menu.Items.Add(new MenuItem { Header = "Mark as Confidential" });
editor.EditorContextMenuStrip = menu;
A month later her senior accountant came back with a refinement: "Mark as Confidential" should only show up when the user had actually selected some text. Otherwise it was confusing. Karolina did not want to maintain two menus, so she kept her custom menu and subscribed to the ContextMenuShowing event to toggle the item's visibility right before the menu appeared.
editor.ContextMenuShowing += (sender, e) =>
{
// e.OffsetMousePosition gives the mouse position relative to the editor.
bool hasSelection = !string.IsNullOrEmpty(editor.SelectedHtml);
confidentialItem.Visibility = hasSelection
? Visibility.Visible
: Visibility.Collapsed;
};
Two patterns, one decision tree. Replace the whole menu through EditorContextMenuStrip when your domain commands are different enough that the editor's defaults would confuse users. Keep the default (or your custom) menu and subscribe to ContextMenuShowing when you need contextual tweaks based on the current selection or cursor position. Karolina ended up using both -- the assignment to set the baseline, the event to keep it honest.