Document Editor | Shapes, Pictures & Tables
The document editor inserts three kinds of object, and highlights text. All of it is on the shared
DocumentEditorController, and all of it is already wired into DocumentEditorView’s toolbar on both
hosts.
var c = editor.Controller!;
c.InsertShape(ShapeGeometry.Ellipse, width: 160, height: 120);c.InsertImage(bytes, "image/png", width: 240); // height follows the image's ratioc.InsertTable(rows: 3, columns: 4);Everything is inline, and that is a real limitation
Section titled “Everything is inline, and that is a real limitation”An object inserted here is a wp:inline — never a wp:anchor. It sits in the text flow and
behaves like a very large character: it wraps with the line it is on, and it moves as text is typed
before it.
That is a genuine difference from Word, where a shape can be anchored to a position on the page with text wrapping around it. The document view is a reflow engine — one continuous column, no pagination, no fixed page positions — so a floating object could be written to the file perfectly well and then never drawn anywhere near where it claimed to be. Writing one would produce a document that looked right in Word and wrong here, which is the worse of the two failures.
An object counts as one character
Section titled “An object counts as one character”For every purpose the caret has, an inline object is exactly one character wide:
- one arrow-key press steps over it
- one backspace or delete removes the whole thing
- a selection that touches it takes all of it
This matters more than it sounds. The layout engine has always counted an inline drawing as one position; before this release the editor’s own offset arithmetic skipped it, so every caret position after a picture was off by one — clicking after an image put the caret in the wrong place, and typing landed one character away from where it looked like it would. That is fixed, and the offset space is now the same on both sides.
Shapes
Section titled “Shapes”Twenty preset geometries, in Shiny.Controls.Office.Shapes:
Rectangle, RoundedRectangle, Ellipse, Triangle, RightTriangle, Diamond, Line,
RightArrow, LeftArrow, UpArrow, DownArrow, Pentagon, Hexagon, Star5, Chevron,
Parallelogram, Trapezoid, Plus, Can, Cloud.
It is the same enum and the same path builder the slide editor uses. A rounded rectangle is the same shape whichever file it came out of, which is the point of having moved the geometry into a neutral namespace rather than leaving it on the presentation side.
c.InsertShape( ShapeGeometry.RightArrow, width: 200, height: 80, fill: new ArgbColor(255, 0x44, 0x72, 0xC4), outline: null, text: "Next");A shape’s text is drawn centred inside it and wrapped to it, and is set at insert time. It has no
caret of its own: the text lives in a w:txbxContent, which is its own little document body, and
giving it a caret means a second nested editing context rather than another run in the paragraph.
DrawingML shapes reach a Word file through a Microsoft extension namespace
(wordprocessingShape, 2010) rather than anything ECMA-376 defined — the original answer was VML. The
VML mc:Fallback is not written, so a shape is simply absent in Word 2007 rather than wrong.
Tables
Section titled “Tables”c.InsertTable(rows: 3, columns: 4);A table is a block, so it goes after the paragraph the caret is in rather than inside it — OOXML
has no way to put a w:tbl in the middle of a w:p. Word splits the paragraph in that case; this
places the table on the boundary below, which loses nothing and never divides a sentence someone was
in the middle of writing. An empty paragraph is added after it, because a body may not end with a
table and one that does is a file Word offers to repair.
The table is sized in percent rather than twips, so it fills the measure it is dropped into and keeps doing so when the page margins change. Typing in its cells works; changing its structure after the fact — adding rows, merging cells — does not yet.
Selecting and resizing
Section titled “Selecting and resizing”Click an object to select it: a frame appears with eight resize handles.
- a corner handle keeps the aspect ratio
- an edge handle changes one dimension
- the whole drag is one undo step, not one per pointer sample
An object cannot be dragged to a new position. It is in the text flow, and the caret is what moves it — cut the character and paste it elsewhere, or type around it.
Both DocumentEditor implementations already drive this from their own pointer handling. If you are
driving the pointer yourself:
c.ObjectAt(x, y); // DocumentPosition?, in viewport coordinatesc.SelectObject(position);c.SelectedInline; // InlineImage or InlineShapec.SelectedObjectBounds(); // document coordinatesc.SelectedObjectHandles(); // the eight ShapeHandle rectsc.DeleteSelectedObject();
c.BeginObjectDrag(x, y); // true when it took the gesturec.DragObject(x, y);c.EndObjectDrag();BeginObjectDrag returning false is the signal that the gesture belongs to the text caret instead,
which is what lets a host call it first and fall through to ordinary click-and-drag selection without
knowing anything about objects.
Dropping image files in
Section titled “Dropping image files in”Dragging an image file onto the editor inserts it at the point it landed. It is on by default.
<DocumentEditorView Document="document" AllowFileDrop="true" DropRejected="OnRejected" /><office:DocumentEditorView x:Name="Editor" Document="{Binding Document}" />Editor.DropRejected += (_, e) => Toast(e.Reason); // MAUIDropRejected fires for a file over 32MB or in a format OOXML cannot store. It is an event rather
than a message the editor draws itself, because there is nowhere inside a canvas to put one that would
not be painted over on the next repaint — and a host that already has a toast should use it.
| Where a file drag works | |
|---|---|
| Blazor | everywhere |
| MAUI | Windows, iOS/iPadOS, Mac Catalyst |
| MAUI | ⚠️ not Android (no file drag from a file manager) or the AppKit/GTK heads (no DropGestureRecognizer implementation behind them) |
On the platforms without it, the toolbar’s picture button is the gesture — which is the one those platforms have anyway.
The drop listener is attached to the canvas, not the toolbar, so dropping a picture onto the Bold button does nothing.
ImageContentTypes.ByExtension is the accepted list: PNG, JPEG, GIF, BMP, TIFF and WebP. SVG is
deliberately not on it — both formats can hold one, but only as a companion to a rasterised fallback
that Office generates when it inserts one, and embedding the vector alone gives a picture that is blank
everywhere except recent Office.
Highlighting
Section titled “Highlighting”c.SetHighlight(new ArgbColor(255, 255, 255, 0)); // null clears itc.ToggleHighlight(color); // what a toolbar button doesc.CaretFormat.Highlight; // what is under the caretWord’s w:highlight takes a name from a closed list of sixteen, not a colour — there is no way to
say “this exact orange”. HighlightPalette is that list, and it is what both toolbars offer:
foreach (var swatch in HighlightPalette.Swatches) // Name, DisplayName, Color ...
HighlightPalette.NameOf(color); // the w:highlight value, or "none" for nullHighlightPalette.ColorOf("yellow"); // the other wayBecause every swatch on offer is one of Word’s named values, nothing is approximated in either
direction. NameOf only falls back to a nearest match for a colour that came from somewhere else —
such as a deck authored in PowerPoint, where a:highlight holds an arbitrary colour.
The toolbar draws it as a split button: the swatch applies the last colour used, and the chevron opens the gallery to change it or clear it. The slide editor uses the same palette and the same button, so one highlight control behaves identically over both file types.


