Keep custom buttons in sync

    A formatting button should reflect the text at the caret: Bold should appear pressed on bold text, and table commands should be available when relevant. Handle SelectionChanged and query StateQuery to keep your own buttons in step with the current selection.

    A host application's ribbon above the WPF HTML editor, with its Bold and Italic toggle buttons lit and its Bullet list toggle unlit, because the caret sits inside a bold italic run and the ribbon reads that state from the editor's StateQuery service
    A host application's ribbon above the WPF HTML editor, with its Bold and Italic toggle buttons lit and its Bullet list toggle unlit, because the caret sits inside a bold italic run and the ribbon reads that state from the editor's StateQuery service

    Two members support this. The SelectionChanged routed event on WpfHtmlEditor fires whenever the caret moves or the selection changes. The StateQuery service answers formatting questions such as IsBold(), IsItalic(), IsUnorderedList(), and more.

    Subscribe to the event in the editor's Loaded handler, then push the returned state into your view model on each callback, as shown below.

    private void ContractEditor_OnLoaded(object sender, RoutedEventArgs e)
    {
        ContractEditor.SelectionChanged += ContractEditor_SelectionChanged;
    }
    
    private void ContractEditor_SelectionChanged(object sender, RoutedEventArgs e)
    {
        var state = ContractEditor.StateQuery;
        var vm = (RibbonViewModel)DataContext;
        vm.IsBold = state.IsBold();
        vm.IsItalic = state.IsItalic();
        vm.IsUnderline = state.IsUnderline();
        vm.IsBulletList = state.IsUnorderedList();
        vm.IsNumberList = state.IsOrderedList();
        vm.IsAlignLeft = state.IsJustifyLeft();
        vm.IsAlignCenter = state.IsJustifyCenter();
        vm.IsAlignRight = state.IsJustifyRight();
        vm.ActiveFontFamily = state.GetActiveFontFamilyName();
        vm.ActiveFontSize = state.GetActiveFontSize();
        vm.CanUndo = state.CanUndo();
        vm.CanRedo = state.CanRedo();
        vm.CanPaste = state.CanPaste();
    }
    Private Sub ContractEditor_OnLoaded(sender As Object, e As RoutedEventArgs)
        AddHandler ContractEditor.SelectionChanged, AddressOf ContractEditor_SelectionChanged
    End Sub
    
    Private Sub ContractEditor_SelectionChanged(sender As Object, e As RoutedEventArgs)
        Dim state = ContractEditor.StateQuery
        Dim vm = CType(DataContext, RibbonViewModel)
        vm.IsBold = state.IsBold()
        vm.IsItalic = state.IsItalic()
        vm.IsUnderline = state.IsUnderline()
        vm.IsBulletList = state.IsUnorderedList()
        vm.IsNumberList = state.IsOrderedList()
        vm.IsAlignLeft = state.IsJustifyLeft()
        vm.IsAlignCenter = state.IsJustifyCenter()
        vm.IsAlignRight = state.IsJustifyRight()
        vm.ActiveFontFamily = state.GetActiveFontFamilyName()
        vm.ActiveFontSize = state.GetActiveFontSize()
        vm.CanUndo = state.CanUndo()
        vm.CanRedo = state.CanRedo()
        vm.CanPaste = state.CanPaste()
    End Sub

    Bind the ribbon toggles in XAML to these properties, for example IsChecked="{Binding IsBold}" and IsChecked="{Binding IsItalic}". Bind Undo/Redo buttons to IsEnabled="{Binding CanUndo}" and IsEnabled="{Binding CanRedo}". As long as RibbonViewModel raises PropertyChanged on each setter, every toggle and button updates automatically as the caret moves.

    Two states of a WPF host application with a custom MVVM ribbon above the HTML editor: with the bold phrase selected the ribbon Bold button is lit, and with the italic phrase selected the Italic button is lit, driven by the editor SelectionChanged event.
    Two states of a WPF host application with a custom MVVM ribbon above the HTML editor: with the bold phrase selected the ribbon Bold button is lit, and with the italic phrase selected the Italic button is lit, driven by the editor SelectionChanged event.

    The StateQuery service exposes many additional context queries beyond the formatting toggles shown above, including IsStrikeThrough(), IsSubscript(), IsSuperscript(), IsHyperLink(), IsImage(), IsTable(), IsTableCell(), IsActiveOrAncestorElementHyperLink(), IsActiveOrAncestorElementTable(), GetActiveForeColor(), GetActiveHighlightColor(), GetActiveHeaderTitleNumber(), IsActiveElementHeaderTitle(), CanCut(), CanCopy(), and CanDelete(). Use these to add more ribbon features with the same event-subscription pattern.

    • Hook the routed SelectionChanged event on WpfHtmlEditor to be notified whenever the caret or selection moves.
    • Inside the handler, call editor.StateQuery.IsBold(), .IsItalic(), .IsUnorderedList(), etc. to learn the caret context.
    • Push the values into your view-model properties so any bound ToggleButton.IsChecked and IsEnabled binding updates automatically.

    Ask your AI to do this

    Connect the SpiceLogic MCP server, then give your coding assistant this prompt.

    I use the SpiceLogic WPF HTML Editor. Help me keep my custom formatting buttons in sync with the current selection. Confirm the exact API names, types and defaults with the SpiceLogic MCP documentation, then show the changes for my project.

    Last updated on Oct 9, 2026

    Put this into practice.

    Clone the C# and VB.NET sample projects from GitHub. Start with Quickstart, then explore the feature samples.

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