Replacing the editor's right-click context menu

Mei-Lin works on the sales CRM at a logistics company. Sales reps spend their day inside an account-detail screen attaching notes to customer records: call summaries, follow-up reminders, snippets pasted from emails. She uses WinFormHtmlEditor as the note editor and her product manager came to her with a clear ask: when a rep right-clicks inside a note, they should see two commands that don't exist in the default menu -- Link to Ticket... and Convert Selection to Task.

The default right-click menu in WinFormHtmlEditor is a reasonable editing menu: cut/copy/paste, table commands, image properties. But it's not the right menu for a CRM note. Mei-Lin wanted to replace it entirely.

Replace the menu via EditorContextMenuStrip

The editor exposes a single property for this: EditorContextMenuStrip, of type System.Windows.Forms.ContextMenuStrip. Assign your own strip and the editor uses it whenever the user right-clicks inside the document surface.

private void NoteEditorForm_Load(object sender, EventArgs e)
{
    var menu = new ContextMenuStrip();
    var linkToTicket = new ToolStripMenuItem("Link to Ticket...");
    linkToTicket.Click += (s, args) =>
    {
        var ticketId = TicketPicker.Show(this);
        if (ticketId != null)
        {
            string anchor = $"<a href=\"crm://ticket/{ticketId}\">#{ticketId}</a>";
            htmlEditor1.Content.InsertHtmlAtCaret(anchor);
        }
    };
    var convertToTask = new ToolStripMenuItem("Convert Selection to Task");
    convertToTask.Click += (s, args) =>
    {
        string selected = htmlEditor1.Selection.GetSelectedHtml();
        if (!string.IsNullOrWhiteSpace(selected))
            TaskService.CreateFromHtml(currentAccount.Id, selected);
    };
    menu.Items.Add(linkToTicket);
    menu.Items.Add(new ToolStripSeparator());
    menu.Items.Add(convertToTask); // Hand the strip to the editor. From now on, right-clicking inside the    // note shows this menu instead of the built-in one.    htmlEditor1.EditorContextMenuStrip = menu;}
Private Sub NoteEditorForm_Load(sender As Object, e As EventArgs)
    Dim menu = New ContextMenuStrip()
    Dim linkToTicket = New ToolStripMenuItem("Link to Ticket...")
    linkToTicket.Click += Sub(s, args)
                              Dim ticketId = TicketPicker.Show(Me)
                              If ticketId IsNot Nothing Then
                                  Dim anchor As String = $"<a href=""crm://ticket/{ticketId}"">#{ticketId}</a>"
                                  htmlEditor1.Content.InsertHtmlAtCaret(anchor)
                              End If
                          End Sub
    Dim convertToTask = New ToolStripMenuItem("Convert Selection to Task")
    convertToTask.Click += Sub(s, args)
                               Dim selected As String = htmlEditor1.Selection.GetSelectedHtml()
                               If Not String.IsNullOrWhiteSpace(selected) Then TaskService.CreateFromHtml(currentAccount.Id, selected)
                           End Sub
    menu.Items.Add(linkToTicket)
    menu.Items.Add(New ToolStripSeparator())
    menu.Items.Add(convertToTask) ' Hand the strip to the editor. From now on, right-clicking inside the    // note shows this menu instead of the built-in one.    htmlEditor1.EditorContextMenuStrip = menu;}
End Sub

[IMAGE: editor-context-menu-strip.png -- right-click menu showing Link to Ticket and Convert to Task in place of the default menu]

Disable items based on current state

Mei-Lin's PM came back the next day with a refinement: "Convert to Task" should be greyed out when there's nothing selected. The EditorContextMenuStrip is a normal Windows Forms ContextMenuStrip, so she wired up its Opening event:

menu.Opening += (s, args) =>
{
    string selected = htmlEditor1.Selection.GetSelectedHtml();
    convertToTask.Enabled = !string.IsNullOrWhiteSpace(selected);
};
menu.Opening += Sub(s, args)
                    Dim selected As String = htmlEditor1.Selection.GetSelectedHtml()
                    convertToTask.Enabled = Not String.IsNullOrWhiteSpace(selected)

[IMAGE: context-menu-opening-state.png -- menu with Convert to Task disabled because there is no selection]

The ContextMenuShowing event: a notification hook

Mei-Lin also wanted to track which parts of a note reps right-click on, so the team could decide where to put the next CRM-specific shortcut. The editor exposes a ContextMenuShowing event that fires whenever the built-in menu is about to appear. The event args give you the cursor position relative to the editor, which is enough for analytics:

htmlEditor1.ContextMenuShowing += (sender, e) =>
{
    // e.OffsetMousePosition is the cursor location relative to the editor surface.
    AnalyticsClient.Track(
        "NoteEditorRightClick",
        new { x = e.OffsetMousePosition.X, y = e.OffsetMousePosition.Y });
};

One thing worth knowing: ContextMenuShowingEventArgs only carries OffsetMousePosition. There's no Cancel, no MenuItems collection, no way to suppress or mutate the built-in menu from inside this event. If you want a completely different menu (as Mei-Lin did), the supported path is EditorContextMenuStrip. The event is for observation, not modification.

[IMAGE: context-menu-showing-event.png -- event firing as the built-in menu appears, with the offset coordinates highlighted]

In production, reps started using Link to Ticket dozens of times a day per account. The cross-references between notes and tickets now flow into the CRM's knowledge graph automatically. Mei-Lin's PM filed a follow-up to add a third item -- Insert Account Name -- and she shipped it the same afternoon by adding one more ToolStripMenuItem to the strip she built on day one.

Last updated on May 15, 2026