Useful Events
The WpfHtmlEditor control raises a number of events as the user types, selects, pastes, and switches editor modes. This page documents the five events that customer projects subscribe to most often. For events not covered here (low-level element clicks, file load/save notifications, error reporting, status bar messages, spell-check completion) see the companion page Other Useful Events.
All five events are declared on the partial class WpfHtmlEditor in the namespace SpiceLogic.HtmlEditor.WPF. Four of the five are exposed as WPF RoutedEvents (and so can be subscribed in XAML and bubble up the visual tree); HtmlChanged is a plain CLR EventHandler<EventArgs> by design (routed events have noticeable per-fire cost and a CLR event lets the editor cheaply check whether any handler is attached). In every example, MyEditor is an instance declared in XAML as <ed:WpfHtmlEditor x:Name="MyEditor" />.
HtmlChanged Event
Occurs whenever the HTML of the document changes. This includes typing, formatting toolbar clicks, programmatic edits, and changes inside the <head> element (for example a header style block edited by customer code).
Syntax
public event EventHandler<EventArgs> HtmlChanged;Event data
The handler receives a plain System.EventArgs. The new document HTML can be read from the editor instance via the DocumentHtml or BodyHtml dependency properties (or the underlying Content service).
Remarks
This is a plain CLR event, not a RoutedEvent -- the editor uses a CLR event here on purpose. The event fires after the document HTML has actually changed; reading DocumentHtml inside the handler returns the new value. The handler runs on the UI thread, so debounce expensive work (DispatcherTimer, etc.) rather than re-serializing on every keystroke.
Example
// Drive an "is dirty?" flag from HtmlChanged.
MyEditor.HtmlChanged += OnHtmlChanged;
private bool _isDirty;
private void OnHtmlChanged(object sender, EventArgs e)
{
_isDirty = true;
SaveButton.IsEnabled = true;
StatusText.Text = "Modified (body length = "
+ MyEditor.BodyHtml.Length + ")";
}Pasting Event
Raised when the user pastes content into the editor (Ctrl+V, the toolbar Paste button, the toolbar Paste-from-Word button, and the context-menu Paste item all route through this event). Handlers can inspect the HTML the editor is about to insert, modify it, or cancel the paste entirely.
Syntax
public event PastingEventHandler Pasting;
public delegate void PastingEventHandler(object sender, PastingHtmlEventArgs e);Event data
Members of PastingHtmlEventArgs (derives from RoutedEventArgs and implements the cross-platform IPastingHtmlEventArgs contract):
| Member | Type | Description |
|---|---|---|
| e.PastingHtml | string (get/set) | The HTML the editor is about to insert. The handler may overwrite this property to inject sanitized HTML. |
| e.Cancel | bool (get/set) | Set to true to abort the paste operation. |
| e.IsModified | bool (get) | Set to true automatically when the handler assigns a different value to PastingHtml. |
| e.IsPastingFromMsWord | bool (get) | true when the clipboard content was identified as MS Word HTML, or the user explicitly chose Paste from Word. |
Remarks
Pasting is a WPF RoutedEvent: handlers attached in XAML with Pasting="..." work, and the event bubbles up the visual tree. If the user has enabled the MsIePasteBehavior option, the editor delegates the actual paste to MSHTML and PastingHtml may be null. In that mode the handler can still cancel the paste but cannot inspect or rewrite the HTML.
Example
// Sanitize incoming HTML, cancelling pastes that try to inject <script>.
MyEditor.Pasting += OnPasting;
private void OnPasting(object sender, PastingHtmlEventArgs e)
{
if (e.PastingHtml == null)
return; // MsIePasteBehavior is on; nothing to inspect.
if (e.PastingHtml.IndexOf("<script", StringComparison.OrdinalIgnoreCase) >= 0)
{
e.Cancel = true;
return;
}
e.PastingHtml = e.PastingHtml.Replace(
"style=\"font-family: Calibri;\"", string.Empty);
}SelectionChanged Event
Occurs whenever the current selection inside the document changes: when the user moves the caret, drags out a new range, or programmatic API calls update the selection.
Syntax
public event RoutedEventHandler SelectionChanged;Event data
The handler receives a standard RoutedEventArgs. Read the current selection from the editor services: MyEditor.Selection.GetSelectionInfo() returns a SelectionInfo with StartIndex and Length; MyEditor.StateQuery.GetActiveHtmlElement() returns the element under the caret; the formatting / state-query services expose the current bold/italic/font flags.
Remarks
This is a WPF RoutedEvent registered with RoutingStrategy.Bubble. Avoid heavy work inside the handler -- the event can fire repeatedly while the user drags the mouse to extend a selection.
Example
// Show the current selection range in a status bar.
MyEditor.SelectionChanged += OnSelectionChanged;
private void OnSelectionChanged(object sender, RoutedEventArgs e)
{
var info = MyEditor.Selection.GetSelectionInfo();
if (info == null) return;
StatusBarText.Text = "Selection: start=" + info.StartIndex
+ ", len=" + info.Length;
}EditorModeChanged Event
Raised when the editor switches between WysiwygDesign, HtmlEdit (raw HTML source) and ReadOnlyPreview modes. The switch can come from the toolbar mode buttons or from setting the EditorMode dependency property in code.
Syntax
public event RoutedEventHandler EditorModeChanged;Event data
The handler receives a standard RoutedEventArgs. Read the new mode from MyEditor.EditorMode (type EditorModes).
Remarks
This is a WPF RoutedEvent. Use it to enable/disable surrounding toolbars or to persist the user's preferred mode between sessions.
Example
// Mirror the mode in the chrome and persist the user's preference.
MyEditor.EditorModeChanged += OnEditorModeChanged;
private void OnEditorModeChanged(object sender, RoutedEventArgs e)
{
bool isDesign = MyEditor.EditorMode == EditorModes.WysiwygDesign;
FormatPainterButton.IsEnabled = isDesign;
PreviewBanner.Visibility =
MyEditor.EditorMode == EditorModes.ReadOnlyPreview
? Visibility.Visible : Visibility.Collapsed;
Properties.Settings.Default.LastEditorMode = MyEditor.EditorMode.ToString();
Properties.Settings.Default.Save();
}ContextMenuShowing Event
Fires when the user right-clicks inside the editor's client area, just before the editor's default context menu is displayed. Handlers can inspect the mouse position and substitute a custom context menu.
Syntax
public event ContextMenuShowingEventHandler ContextMenuShowing;
public delegate void ContextMenuShowingEventHandler(object sender, ContextMenuShowingEventArgs e);Event data
Members of ContextMenuShowingEventArgs (derives from RoutedEventArgs):
| Member | Type | Description |
|---|---|---|
| e.OffsetMousePosition | System.Drawing.Point (get) | The position of the mouse cursor relative to the editor's client area, in pixels. |
Remarks
This is a WPF RoutedEvent. If you want to replace the default context menu entirely, assign your custom ContextMenu to the editor's EditorContextMenuStrip property -- the editor will use it automatically; subscribing to this event is only needed when you want to show a one-off menu built from what was clicked.
Example
// Pop a one-off WPF ContextMenu at the cursor.
MyEditor.ContextMenuShowing += OnContextMenuShowing;
private void OnContextMenuShowing(object sender, ContextMenuShowingEventArgs e)
{
var menu = new ContextMenu();
menu.Items.Add(new MenuItem { Header = "Custom action..." });
menu.PlacementTarget = MyEditor;
menu.IsOpen = true;
}See also
For events not covered here (HtmlElementClicked, HtmlElementMouseDown, FileOpened, FileSaved, ErrorOccurred, StatusChanged, SpellCheckCompleted) see the Other Useful Events page in this section.