Overriding WPF Editor Toolbar Button Icons, Tooltips, and Click Behavior

    The WpfHtmlEditor control ships with built-in toolbar buttons, and sooner or later their default icon, tooltip, or click behavior will not fit your app - an icon that clashes with your icon set, a tooltip that needs your app's own wording, or, in an MVVM-style application, a click handler that bypasses your view-model commands entirely. Every user action in an MVVM-style WPF app should flow through view-model commands so it can be tested and audited consistently, and the control's default Save button breaks that pattern: clicking it opens a standard SaveFileDialog and writes the HTML straight to disk, bypassing your command layer. This page shows how to use ToolbarItemOverrider to replace a button's icon, tooltip, and click behavior, using the Save button as the example: routing the save action through your own command instead of the file system.

    WPF HTML Editor with the factory Save button rerouted through an MVVM ViewModel command (writing to the support-ticket database) instead of opening a file save dialog.
    WPF HTML Editor with the factory Save button rerouted through an MVVM ViewModel command (writing to the support-ticket database) instead of opening a file save dialog.

    Instead of hiding the factory Save button and adding a separate one, keep it in place and repurpose its click behavior and icon. ToolbarItemOverrider exposes two complementary surfaces for this: the SaveButtonClicked event, which once subscribed skips the default file-dialog flow and routes the click to your handler instead, and the ToolbarItems.Save property, which gives you the live factory Button so you can change its tooltip, hide it, or walk its visual tree to swap the icon, just like any normal Button.

    private void IncidentNoteEditor_OnLoaded(object sender, RoutedEventArgs e) {     var overrider = IncidentNoteEditor.ToolbarItemOverrider;     // Reword the tooltip so operators see "Save to ticket" not just "Save".     overrider.ToolbarItems.Save.ToolTip = "Save to ticket database (Ctrl+S)";     // Hide the New button - operators must never start a fresh blank note.     overrider.ToolbarItems.New.Visibility = Visibility.Collapsed;     // Replace the icon with our app diskette so the toolbar stays visually consistent.     if (VisualTreeHelper.GetChild(overrider.ToolbarItems.Save, 0)is Border border && VisualTreeHelper.GetChild(border, 0)is ContentPresenter presenter && VisualTreeHelper.GetChild(presenter, 0)is Image saveImage)     {         saveImage.Source = new BitmapImage(new Uri("pack://application:,,,/MyConsole;component/Icons/save_db.png", UriKind.Absolute));     }      // Route the click straight through to the MVVM command.     overrider.SaveButtonClicked += RouteToSaveCommand;     overrider.OpenButtonClicked += RouteToLoadCommand; }  private void RouteToSaveCommand(object sender, RoutedEventArgs e) {     var vm = (IncidentNoteViewModel)DataContext;     string html = IncidentNoteEditor.BodyHtml;     if (vm.SaveNoteCommand.CanExecute(html))         vm.SaveNoteCommand.Execute(html); }  private void RouteToLoadCommand(object sender, RoutedEventArgs e) {     var vm = (IncidentNoteViewModel)DataContext;     if (vm.LoadNoteCommand.CanExecute(null))         vm.LoadNoteCommand.Execute(null); }
    Private Sub IncidentNoteEditor_OnLoaded(sender As Object, e As RoutedEventArgs)     Dim overrider = IncidentNoteEditor.ToolbarItemOverrider     ' Reword the tooltip so operators see "Save to ticket" not just "Save".     overrider.ToolbarItems.Save.ToolTip = "Save to ticket database (Ctrl+S)"     ' Hide the New button - operators must never start a fresh blank note.     overrider.ToolbarItems.[New].Visibility = Visibility.Collapsed     ' Replace the icon with our app diskette so the toolbar stays visually consistent.     Dim border As Border = Nothing, presenter As ContentPresenter = Nothing, saveImage As Image = Nothing      If CSharpImpl.__Assign(border, TryCast(VisualTreeHelper.GetChild(overrider.ToolbarItems.Save, 0), Border)) IsNot Nothing AndAlso CSharpImpl.__Assign(presenter, TryCast(VisualTreeHelper.GetChild(border, 0), ContentPresenter)) IsNot Nothing AndAlso CSharpImpl.__Assign(saveImage, TryCast(VisualTreeHelper.GetChild(presenter, 0), Image)) IsNot Nothing Then         saveImage.Source = New BitmapImage(New Uri("pack://application:,,,/MyConsole;component/Icons/save_db.png", UriKind.Absolute))     End If      ' Route the click straight through to the MVVM command.     overrider.SaveButtonClicked += AddressOf RouteToSaveCommand     overrider.OpenButtonClicked += AddressOf RouteToLoadCommand End Sub  Private Sub RouteToSaveCommand(sender As Object, e As RoutedEventArgs)     Dim vm = CType(DataContext, IncidentNoteViewModel)     Dim html As String = IncidentNoteEditor.BodyHtml     If vm.SaveNoteCommand.CanExecute(html) Then vm.SaveNoteCommand.Execute(html) End Sub  Private Sub RouteToLoadCommand(sender As Object, e As RoutedEventArgs)     Dim vm = CType(DataContext, IncidentNoteViewModel)     If vm.LoadNoteCommand.CanExecute(Nothing) Then vm.LoadNoteCommand.Execute(Nothing) End Sub  Private Class CSharpImpl     <System.Obsolete("Please refactor calling code to use normal Visual Basic assignment")>     Shared Function __Assign(Of T)(ByRef target As T, value As T) As T         target = value         Return value     End Function

    With this in place, clicking Save no longer opens a file dialog - the HTML body is passed straight to SaveNoteCommand through your view model.

    WPF HTML Editor Save toolbar button showing the overridden database icon and the custom 'Save to ticket database' tooltip on mouse hover.
    WPF HTML Editor Save toolbar button showing the overridden database icon and the custom 'Save to ticket database' tooltip on mouse hover.

    You can override any factory toolbar action the same way: subscribe to its event to intercept the click and add your own logic (for example, checking a permission flag before allowing copy or paste). Every factory command is overridable - NewButtonClicked, OpenButtonClicked, SaveButtonClicked, CutButtonClicked, CopyButtonClicked, PasteButtonClicked, PasteFromMSWordButtonClicked, PrintButtonClicked, UndoButtonClicked, RedoButtonClicked, BoldButtonClicked, ItalicButtonClicked, UnderlineButtonClicked, StrikeThroughButtonClicked, SubscriptButtonClicked, SuperScriptButtonClicked, TextHighlightColorButtonClicked, FontForeColorButtonClicked, HyperLinkButtonClicked, ImageButtonClicked, YouTubeVideoInsertButtonClicked, OrderedListButtonClicked, UnOrderedListButtonClicked, AlignLeftButtonClicked, AlignCenterButtonClicked, AlignRightButtonClicked, OutdentButtonClicked, IndentButtonClicked, TableInsertButtonClicked, SymbolInsertButtonClicked, HorizontalRuleButtonClicked, FormatResetButtonClicked, BodyStyleButtonClicked, SearchButtonClicked, and SpellCheckButtonClicked.

    • ToolbarItemOverrider.ToolbarItems.X exposes the live factory Button / ToggleButton / ComboBox for icon, tooltip, and visibility tweaks.
    • Subscribing to ToolbarItemOverrider.XButtonClicked suppresses the default behavior and routes the click to your handler instead.
    • Walk the factory button's visual tree to swap the inner Image.Source for a custom icon.

    Last updated on May 15, 2026

    Put this into practice.

    WPF HTML Editor Control ships with free C# and VB.NET sample projects and a 14-day evaluation.

    Prefer a guided look? Book a free live demo with our engineers - live on Zoom or Teams, never a chatbot.