Class DocxBlock
- Namespace
- DocToolkit
- Assembly
- DocToolkit.dll
One block of content in a document built by Create(IEnumerable<DocxBlock>).
The hierarchy is CLOSED: the constructor is private protected, the concrete types are
internal sealed, and a block can only be obtained from one of the factory methods below.
A consumer therefore cannot define a block the writer has never heard of — an unrenderable block
is unrepresentable rather than a runtime failure.
Each factory validates its arguments immediately, so a bad value throws at the line that produced it rather than later inside a Create(IEnumerable<DocxBlock>) call assembling many blocks at once.
public abstract class DocxBlock
- Inheritance
-
DocxBlock
- Inherited Members
Methods
Heading(string, int)
A heading at level, rendered with a real Word heading style so it appears
in the navigation pane and can drive a table of contents.
public static DocxBlock Heading(string text, int level)
Parameters
textstringThe heading's text.
levelint1 to 6, matching HTML
h1–h6. Word itself defines nine; six is the deliberate stopping point. Out of range throws rather than clamping, because a silently demoted heading is only ever noticed in the finished document.
Returns
Exceptions
- ArgumentNullException
textis null.- ArgumentOutOfRangeException
levelis not 1–6.
Image(byte[], double?, double?, string?)
An inline image. PNG and JPEG only, decided by magic bytes rather than by anything the caller
says — a part declaring image/png while holding JPEG bytes renders as a blank frame,
silently.
Size is in points, matching ReplaceImage(byte[], string, byte[], double?, double?). Omit both and the image's intrinsic size at 96 DPI is used; give one and the other scales to preserve the aspect ratio; give both and the image is stretched, distortion accepted as the caller's choice.
altText becomes the drawing's descr, which is what a screen reader
announces. Omit it and the attribute is omitted too, rather than filled with a placeholder:
a generated value like "Image 1" is worse than nothing, because it is read out as though it
described the picture. Supply it for any image carrying meaning; leave it off for one that is
purely decorative.
public static DocxBlock Image(byte[] image, double? widthPoints = null, double? heightPoints = null, string? altText = null)
Parameters
imagebyte[]PNG or JPEG bytes.
widthPointsdouble?Rendered width in points, or null to derive it.
heightPointsdouble?Rendered height in points, or null to derive it.
altTextstringWhat a screen reader announces in place of the image. Null omits it.
Returns
Exceptions
- ArgumentNullException
imageis null.- ArgumentException
imageis empty, or is neither PNG nor JPEG.- ArgumentOutOfRangeException
A supplied size is zero or negative, or the resulting size is larger than a drawing extent can hold — see ReplaceImage(byte[], string, byte[], double?, double?) for the same bound on the editing path.
Paragraph(string)
A body paragraph. Empty text is allowed and produces a blank line.
public static DocxBlock Paragraph(string text)
Parameters
textstring
Returns
Exceptions
- ArgumentNullException
textis null.
Table(IEnumerable<string>, IEnumerable<IEnumerable<object?>>)
A table with a bold header row.
Cell values are typed the same WAY as Create(string, IEnumerable<IEnumerable<object?>>) — bool, DateTime, DateOnly, TimeOnly and TimeSpan are handled by name, and everything else, numbers included, is formatted through InvariantCulture — but they do not always render to the same TEXT, and that is deliberate. A spreadsheet cell stores a typed value that Excel formats on display; a Word table cell stores only text, so the value is rendered here and the rendering is this library's choice. For example:
- Dates use ISO-8601 (
2026-08-06). The workbook path renders the same date in a slashed form whose field order follows the reader's culture —08/06/2026or06/08/2026for this date, depending on the machine. That ambiguity between day-first and month-first readings is precisely what ISO-8601 removes. - A TimeSpan keeps its days (
1.02:03:04). Excel flattens them into hours (26:03:04), which is a different unit convention, not just a different pattern. - A very large decimal, long or ulong keeps
every digit here. The workbook path converts through double first, so it can
show a rounded value —
decimal.MaxValuebecomes7.92281625142643E+28there and stays79228162514264337593543950335here. That is a different number, not a different pattern.
Those examples are illustrative, not an exhaustive list of the differences. What both guarantee identically is that the same input produces the same output on every machine, because neither consults the current culture.
Rows are materialised immediately; mutating the caller's sequence afterwards does not change the block.
A row SHORTER than the header is padded with empty cells: ragged data is normal, and padding discards nothing. A row LONGER than the header throws, and the asymmetry is the point — the surplus values could only be dropped, which is data loss with no signal anywhere. Word would render the table as though it were complete. Same reasoning as Heading(string, int) refusing to clamp an out-of-range level: a loss that only shows up in the finished document is worth more than the convenience of accepting the call.
public static DocxBlock Table(IEnumerable<string> headers, IEnumerable<IEnumerable<object?>> rows)
Parameters
headersIEnumerable<string>rowsIEnumerable<IEnumerable<object>>
Returns
Exceptions
- ArgumentNullException
headersorrowsis null.- ArgumentException
headersis empty, a row is null, or a row has more cells than there are headers.