Avalonia.Controls.RichTextEditor
12.3.0
Prefix Reserved
dotnet add package Avalonia.Controls.RichTextEditor --version 12.3.0
NuGet\Install-Package Avalonia.Controls.RichTextEditor -Version 12.3.0
<PackageReference Include="Avalonia.Controls.RichTextEditor" Version="12.3.0" />
<PackageVersion Include="Avalonia.Controls.RichTextEditor" Version="12.3.0" />
<PackageReference Include="Avalonia.Controls.RichTextEditor" />
paket add Avalonia.Controls.RichTextEditor --version 12.3.0
#r "nuget: Avalonia.Controls.RichTextEditor, 12.3.0"
#:package Avalonia.Controls.RichTextEditor@12.3.0
#addin nuget:?package=Avalonia.Controls.RichTextEditor&version=12.3.0
#tool nuget:?package=Avalonia.Controls.RichTextEditor&version=12.3.0
Avalonia.Controls.RichTextEditor
A rich text editing control for Avalonia UI applications. Provides a FlowDocumentScrollViewer for read-only display and a RichTextEditor control with full editing, selection, keyboard/mouse handling, undo/redo, and extensible highlighting.
Features
- RichTextEditor control with full editing support
- FlowDocumentScrollViewer for read-only document rendering
- Keyboard and mouse input handling
- Caret and selection management
- Extensible highlight layers
- Block adorner system
- Editor toolbar with overflow menu support
Quick Start
<RichTextEditor>
<FlowDocument>
<Paragraph>
<Run>Hello, rich text!</Run>
</Paragraph>
</FlowDocument>
</RichTextEditor>
Dependencies
Avalonia.Controls.Documents
Documentation
See the documentation for more details.
| Product | Versions Compatible and additional computed target framework versions. |
|---|---|
| .NET | net8.0 is compatible. net8.0-android was computed. net8.0-browser was computed. net8.0-ios was computed. net8.0-maccatalyst was computed. net8.0-macos was computed. net8.0-tvos was computed. net8.0-windows was computed. net9.0 was computed. net9.0-android was computed. net9.0-browser was computed. net9.0-ios was computed. net9.0-maccatalyst was computed. net9.0-macos was computed. net9.0-tvos was computed. net9.0-windows was computed. net10.0 is compatible. net10.0-android was computed. net10.0-browser was computed. net10.0-ios was computed. net10.0-maccatalyst was computed. net10.0-macos was computed. net10.0-tvos was computed. net10.0-windows was computed. |
-
net10.0
- Avalonia (>= 12.0.3)
- Avalonia.Controls.ColorPicker (>= 12.0.3)
- Avalonia.Controls.Documents (>= 12.3.0)
- Avalonia.Controls.Documents.Serialization.Rtf (>= 12.3.0)
- AvaloniaUI.Licensing (>= 3.1.2)
-
net8.0
- Avalonia (>= 12.0.3)
- Avalonia.Controls.ColorPicker (>= 12.0.3)
- Avalonia.Controls.Documents (>= 12.3.0)
- Avalonia.Controls.Documents.Serialization.Rtf (>= 12.3.0)
- AvaloniaUI.Licensing (>= 3.1.2)
NuGet packages (1)
Showing the top 1 NuGet packages that depend on Avalonia.Controls.RichTextEditor:
| Package | Downloads |
|---|---|
|
Devolutions.AvaloniaControls.SpreadsheetEditor
An Excel-like spreadsheet editor control for Avalonia UI: a custom grid with cell merging, rich in-cell editing, a formula engine, charts, multi-sheet tabs, undo/redo, and printing. Requires the commercial Avalonia Accelerate packages (a valid Avalonia UI license key must be supplied by the consuming application). |
GitHub repositories
This package is not used by any popular GitHub repositories.
## 12.3.0
Adds to 12.2.3 and removes nothing: every type and member a 12.2.3 build could reference is still there with the same signature, checked against the released packages on every build.
### Features
- Ctrl+Enter (Cmd+Enter on macOS) applies an explicit page break at the caret, replacing any selection, in one undo step: at a block boundary it sets `BreakPageBefore` on the following block, and mid-content it splits the paragraph like Enter and flags the remainder. Backspace at a flagged block merges when the neighbour can merge (removing the break with it) and clears the flag when it cannot.
- `RichTextEditor.ViewMode` switches the editor between `Continuous` (the default column) and `PageLayout` (discrete page sheets, Word's print layout). The switch swaps the hosted view through the `:page-layout` template; the document, caret, selection, and the whole interaction stack carry over, so typing, Ctrl+Enter, and caret navigation work on pages. `PageSize`, `PageMargins`, and `PageGap` configure the sheets (document page setup, then A4/2 cm, as everywhere else).
- Page bands edit in place in page layout, through the editor's one view: every sheet shows the header and footer it resolves as a `NestedDocumentNode` over the band document, and a click into a band switches the editor's selection to the band's. `ActiveDocument` names the band the caret is in (null in the body), `ActiveDocumentChanged` follows it, and `ActivateDocument(document, position)` enters a band or, with null, returns to the body, as Escape does; a document swap while the caret is in a band leaves the editor on the body, a re-template keeps the caret in the band it was in, and a band removed from the document takes its selection with it. One editor, one caret, one toolbar, one set of overlays and components: while the caret is in a band `Selection` is the band's, the toolbar and formatting actions apply to it, the `:band-editing` pseudo-class is set, a frame in `PageBandFocusBrush` marks the band's placement, and `ToolbarTargetAreas.PageBand` lets a tool target bands alone; undo is one stack for the document and its bands. Page-number fields in a band show the sheet's page number and the page count.
- Band authoring, as actions and one toolbar flyout. `EditorActions.GoToHeader` and `GoToFooter` enter the band of the caret's page, creating the document's running band when the page shows none (the continuous view switches to page layout first, as Word switches to print layout); `RemoveHeader` and `RemoveFooter` remove the band the caret is in or the page shows; `DifferentFirstPage` and `DifferentOddAndEvenPages` are toggles with derived state that add or remove the document's first-page and even-page bands; `LinkToPrevious` links the caret's top-level section to the running bands or gives it bands of its own, cloned from what its pages showed; `InsertPageNumber` and `InsertPageCount` insert the fields inside a band; `ReturnToBody` is Escape's command form. Every command is one undo unit, band membership included. `PageBandFlyoutTool` in the toolbar's insert group presents them with the band distance (`RichTextEditor.PageBandDistance`, bound into the page layout template), the context menu offers the fields and the way back inside a band, and the footnote action is body-only.
- `ShowPageBandsInContinuousLayout` (off by default) shows the running header and footer as regions of the continuous view, edited in place like the bands on the sheets; with it on, the band commands stay in the continuous view instead of switching to page layout.
- Footnotes edit as nested documents, the way page bands do: a click into a note switches the editor's selection to the note's, `ActiveDocument` names the note the caret is in, Escape returns to the body, the `:footnote-editing` pseudo-class is set, the frame in `PageBandFocusBrush` marks the note's container, and `ToolbarTargetAreas.Footnote` lets a tool target notes alone. `EditorActions.InsertFootnote` enters the new note after inserting it; `EditorActions.GoToFootnote` enters the note of the anchor the caret sits on or has just passed, as a double-click on an anchor does, and `GoToFootnoteReference` returns to the body right after the note's anchor. A note is a document of its own, so a character delete never crosses its edge and a body selection never reaches into it; the page-number actions are band-only.
- Bringing the caret into view no longer depends on the host scroll viewer having a scrollable layout: while it has none (a host not laid out yet, a headless host), the view scrolls itself, so typing at the end of a paragraph that spans pages reaches its page regardless of which job runs first.
### API additions
- `EditorActionIds` names the `Id` of every built-in action as a `public const string`, so an `EditorActions.GetById` lookup is written against a constant instead of a bare string. The identifiers the `EditorActions` and `IEditorAction` remarks gave as examples were corrected with it: every one of them named something that does not exist.
- `EditorActions.InsertFootnote` registers the footnote insert action, which `All` and `GetById` did not know about; a menu built from `All` offered the two footnote navigation commands but not the one that creates a note.
- Every templated toolbar control declares its parts with `[TemplatePart]` and publishes the names as `public const string Part*` members. Re-templating a tool no longer means reading the source, and a typo in a consumer theme is visible instead of producing a control that silently does nothing.
- `EditorTool.EnsureEditorFocus()` is `protected` instead of internal. Every built-in tool returns focus to the text view before executing an action; without it a consumer-authored tool leaves the caret behind and keyboard input stops reaching the editor.
- `EditorToolbar.EditorHost` binds the toolbar to an editing host that is not a `RichTextEditor`. The toolbar drives whichever of `Editor` and `EditorHost` carries a value.
- `InsertImageAction.ExecuteWith` and `InsertTableAction.ExecuteWithSize` place an image or a table with an explicit size in one call.
- `IBlockPropertyAction<T>` derives from `IPropertyAction<T>`, so one cast reaches both the block and the inline property surface. `ClearValue` is redeclared on `IPropertyAction<T>` with a default forwarding to the untyped member, so an existing implementer is unaffected.
### Behavioural changes
- `RichTextEditor.Save` and `Load` call the synchronous `FlowDocument.Save` and `Load` instead of blocking on the asynchronous pair with `GetAwaiter().GetResult()`, which deadlocked on a UI thread whose message loop the continuation needed.
- `ToolbarGroup` nests. Adding a group to another group's `Tools` threw from a collection-changed handler, which surfaced as an `XamlLoadException` wrapping it at parse time. Overflow descends the tree rather than stopping at the first level.
- `EditorToolbar.ActiveTargetAreas` and `EditorTool.ActiveTargetAreas` are still settable, and the toolbar still overwrites them: it derives the value from the selection on every selection and document change and pushes it onto its tools, so a value written from outside lasts until the caret moves. The per-tool propagation the shipped theme used to do is gone, and a tool that follows the caret binds `IsVisible` to `IsVisibleForTargetArea`.
- A re-template of the editor (a `ViewMode` switch, or assigning `Template`) keeps the caret in the active page band or footnote instead of returning it to the body. A document swap still returns it.
- Invoking a block property action with no value does nothing, matching the inline property actions. `BlockPropertyAction<T>.Execute` threw `NotSupportedException`, and every entry point that invokes an action awaited the resulting task with no observer, so binding a tool to `EditorActions.Margin`, `Padding`, `LineHeight`, `BlockBackground`, `BorderThickness`, `BorderBrush` or `TextAlignmentAction` and clicking it took the host process down. `SetValue` is still how a block property is applied.
- Applying a block property across several blocks is one undo entry on any host. `BlockPropertyAction<T>` reached the undo manager by downcasting the host to the concrete `RichTextEditor`, so a consumer-authored host recorded one unit per affected block; it goes through `ITextEditorHost.TextDocument` now.
- `EditorActions.All` enumerates in declaration order, grouped by category, rather than in a dictionary's iteration order. The declared type is unchanged.
### Fixes
- `GoToHeader` and `GoToFooter` from the continuous view now leave the caret in the band. The command switches `ViewMode` and activates the band in one gesture, but the theme re-templates for the new mode at the next measure pass, and that re-template returned the editor to the body: the view changed to page sheets, `ActiveDocument` went back to null and the caret stayed where it was in the body. A re-template over the same document now keeps the active nested document and its pseudo-class.
- An editor action that fails no longer terminates the host process. Toolbar clicks, menu clicks and keyboard shortcuts arrive on void-returning members that awaited the action's task with no observer, so a faulted task was rethrown on the dispatcher. Two ways in: binding `EditorActions.Margin`, `Padding`, `LineHeight`, `BlockBackground`, `BorderThickness`, `BorderBrush` or `TextAlignment` to a `ButtonTool` or an `EditorMenuItem` and clicking it (a block property action threw `NotSupportedException` from `Execute`), and Ctrl+C / Ctrl+X / Ctrl+V while another process holds the platform clipboard. Every such entry point now awaits in one place that logs the failure and leaves the document unchanged, and invoking a block property action with no value is a no-op, matching the inline property actions.
- Undo restores the caret into the document the edit was in. Page bands and footnotes share the body's undo stack, so one stack interleaves units from several documents; editing a header, clicking into the body and pressing Ctrl+Z reversed the header edit off-screen and dropped the body caret at a body offset numerically equal to a header offset.
- A read-only editor no longer traps keyboard focus. The read-only key gate marked every non-navigation, non-command key handled, and Avalonia's keyboard navigation skips handled events, so Tab and Shift+Tab never left the control. It also consumed Space (a viewer's page-down) and Alt-modified keys (access keys elsewhere on the page). Only the keys that would edit are suppressed now.
- Shift+Enter and Ctrl+Enter over a selection that spans a paragraph boundary now replace the selection the way Enter, typing and paste do: the paragraph mark inside the selection is consumed and the surviving fragments join, instead of leaving two paragraphs with the break inside one of them.
- Switching `ViewMode` releases the outgoing view's caret. It was left attached to the host, so one orphan accumulated per switch, each running a caret update on every keystroke and every layout pass from outside the visual tree and holding its blink timer.
- Entering a nested document with a caret position raises `SelectionChanged` once, not twice. Every toolbar tool re-queries `CanExecute` on that event, so `GoToHeader`, `GoToFooter`, the footnote commands and `InsertFootnote` each ran the whole selection pass twice and handed external subscribers two events for one action.
- `EditorActions.Paste` and `PasteUnformatted` report `CanExecute` as false on a host with no document. The condition was written so that a null document made the whole expression true, which presented an enabled, inert Paste button. `RichTextEditor` never reaches it; the defect was confined to a consumer's own `ITextEditorHost`.
### Notes
- `ITextEditorHost.Undo()` and `Redo()` keep their default implementations, which forward straight to the undo manager and skip the caret restoration the members' own remarks describe. A host that means to restore the caret overrides both.
- `ITextEditorHost.SelectionFlyout` and `ShowSelectionFlyout` have defaults that forward to the internal presenter contract, so a host that shows no mini-bar leaves them alone.