using DocumentFormat.OpenXml; using DocumentFormat.OpenXml.Wordprocessing; namespace MiniMaxAIDocx.Core.Samples; /// /// Exhaustive reference for every RunProperties (w:rPr) child element in OpenXML. /// Each method demonstrates one formatting category with full XML doc comments, /// unit explanations, and gotchas. All code compiles against DocumentFormat.OpenXml 3.5.1. /// public static class CharacterFormattingSamples { // ────────────────────────────────────────────────────────────────── // 1. Font Family (w:rFonts) // ────────────────────────────────────────────────────────────────── /// /// Sets the font family on a run using all four font slots defined in OOXML. /// /// The four font slots: /// /// Ascii — Used for characters in the Basic Latin range (U+0000–U+007F). /// This is the primary slot for English text. /// HighAnsi — Used for characters above U+007F that are NOT East Asian /// and NOT Complex Script. Covers Latin Extended, Greek, Cyrillic, etc. /// Typically set to the same value as Ascii. /// EastAsia — Used for CJK Unified Ideographs (U+4E00–U+9FFF), /// Hiragana, Katakana, Hangul, CJK Compatibility, etc. /// Set this for Chinese / Japanese / Korean content. /// ComplexScript — Used for Complex Script (BiDi) ranges: /// Arabic (U+0600–U+06FF), Hebrew (U+0590–U+05FF), Thai, Devanagari, /// and other right-to-left or complex-shaping scripts. /// /// /// /// Gotcha: If HighAnsi is not set, Word may fall back to a different font /// for characters like accented Latin (e.g., "e" uses Ascii, "e-acute" uses HighAnsi). /// Always set both Ascii and HighAnsi together for consistent Western text rendering. /// /// /// Gotcha: RunFonts also supports a Hint attribute /// () that tells Word which slot to prefer when a /// character could belong to multiple ranges. Values: Default, EastAsia, ComplexScript. /// /// public static void ApplyFontFamily(Run run) { var rPr = run.GetOrCreateRunProperties(); rPr.RunFonts = new RunFonts { // Basic Latin characters (U+0000–U+007F) Ascii = "Calibri", // Non-CJK, non-complex characters above U+007F (Latin Extended, Greek, Cyrillic) HighAnsi = "Calibri", // CJK Ideographs, Hiragana, Katakana, Hangul EastAsia = "SimSun", // Arabic, Hebrew, Thai, Devanagari and other complex scripts ComplexScript = "Arial", // Hint tells Word which font slot to prefer for ambiguous characters. // FontTypeHintValues.EastAsia makes Word prefer the EastAsia slot. Hint = FontTypeHintValues.EastAsia }; } // ────────────────────────────────────────────────────────────────── // 2. Font Size (w:sz, w:szCs) // ────────────────────────────────────────────────────────────────── /// /// Sets the font size on a run. /// /// Unit: w:sz is in half-points. 12pt = 24 half-points, 10.5pt = 21 half-points. /// /// /// w:szCs (FontSizeComplexScript) controls the size for Complex Script text /// (Arabic, Hebrew, etc.). It must be set separately — it does NOT inherit from w:sz. /// If you only set w:sz, Arabic/Hebrew text may render at a different size. /// /// /// The run to modify. /// Size in typographic points (e.g., 12.0 for 12pt). public static void ApplyFontSize(Run run, double points) { var rPr = run.GetOrCreateRunProperties(); // Convert points to half-points: 12pt → "24" var halfPoints = ((int)(points * 2)).ToString(); // w:sz — size for Latin / East Asian text rPr.FontSize = new FontSize { Val = halfPoints }; // w:szCs — size for Complex Script text (Arabic, Hebrew, Thai, etc.) // Must be set independently; does NOT inherit from w:sz. rPr.FontSizeComplexScript = new FontSizeComplexScript { Val = halfPoints }; } // ────────────────────────────────────────────────────────────────── // 3. Bold and Italic (w:b, w:bCs, w:i, w:iCs) // ────────────────────────────────────────────────────────────────── /// /// Applies bold and italic formatting to a run. /// /// Complex Script variants: w:bCs and w:iCs control bold/italic for Complex /// Script text (Arabic, Hebrew). They must be set independently. /// /// /// Gotcha: Bold with no Val attribute means "true". /// To explicitly disable bold (override a style), set Val = false. /// An absent element means "inherit from style". /// /// public static void ApplyBoldItalic(Run run) { var rPr = run.GetOrCreateRunProperties(); // Bold for Latin / East Asian text // (no val) is equivalent to rPr.Bold = new Bold(); // Bold for Complex Script (Arabic, Hebrew, etc.) rPr.BoldComplexScript = new BoldComplexScript(); // Italic for Latin / East Asian text rPr.Italic = new Italic(); // Italic for Complex Script rPr.ItalicComplexScript = new ItalicComplexScript(); // To DISABLE bold (e.g., override a bold style), explicitly set Val = false: // rPr.Bold = new Bold { Val = false }; } // ────────────────────────────────────────────────────────────────── // 4. Underline (w:u) — ALL UnderlineValues // ────────────────────────────────────────────────────────────────── /// /// Demonstrates every underline style available in OOXML. /// /// Underline color: By default, the underline color matches the text color. /// Override with Color (hex) and/or ThemeColor. /// /// /// All 18 styles: Single, Words, Double, Thick, Dotted, DottedHeavy, /// Dash, DashedHeavy, DashLong, DashLongHeavy, DotDash, DashDotHeavy, /// DotDotDash, DashDotDotHeavy, Wave, WavyHeavy, WavyDouble, None. /// /// public static void ApplyAllUnderlineStyles(Run run) { var rPr = run.GetOrCreateRunProperties(); // ── Standard underlines ── // Single: standard single underline (most common) rPr.Underline = new Underline { Val = UnderlineValues.Single }; // Words: underlines words only, not spaces // rPr.Underline = new Underline { Val = UnderlineValues.Words }; // Double: two parallel lines // rPr.Underline = new Underline { Val = UnderlineValues.Double }; // Thick: single thick line // rPr.Underline = new Underline { Val = UnderlineValues.Thick }; // ── Dotted variants ── // Dotted: dots // rPr.Underline = new Underline { Val = UnderlineValues.Dotted }; // DottedHeavy: thick dots // rPr.Underline = new Underline { Val = UnderlineValues.DottedHeavy }; // ── Dash variants ── // Dash: short dashes // rPr.Underline = new Underline { Val = UnderlineValues.Dash }; // DashedHeavy: thick short dashes // rPr.Underline = new Underline { Val = UnderlineValues.DashedHeavy }; // DashLong: long dashes // rPr.Underline = new Underline { Val = UnderlineValues.DashLong }; // DashLongHeavy: thick long dashes // rPr.Underline = new Underline { Val = UnderlineValues.DashLongHeavy }; // ── Dash-dot combinations ── // DotDash: alternating dot-dash (._._.) // rPr.Underline = new Underline { Val = UnderlineValues.DotDash }; // DashDotHeavy: thick dot-dash // rPr.Underline = new Underline { Val = UnderlineValues.DashDotHeavy }; // DotDotDash: dot-dot-dash (.._.._) // rPr.Underline = new Underline { Val = UnderlineValues.DotDotDash }; // DashDotDotHeavy: thick dot-dot-dash // rPr.Underline = new Underline { Val = UnderlineValues.DashDotDotHeavy }; // ── Wave variants ── // Wave: wavy line // rPr.Underline = new Underline { Val = UnderlineValues.Wave }; // WavyHeavy: thick wavy line // rPr.Underline = new Underline { Val = UnderlineValues.WavyHeavy }; // WavyDouble: double wavy line // rPr.Underline = new Underline { Val = UnderlineValues.WavyDouble }; // ── Remove underline ── // None: explicitly remove underline (override style) // rPr.Underline = new Underline { Val = UnderlineValues.None }; // ── Underline with custom color ── // rPr.Underline = new Underline // { // Val = UnderlineValues.Single, // Color = "FF0000", // Red underline, independent of text color // ThemeColor = ThemeColorValues.Accent1 // Or use theme color // }; } // ────────────────────────────────────────────────────────────────── // 5. Text Color (w:color) // ────────────────────────────────────────────────────────────────── /// /// Sets the text color on a run using hex value and/or theme colors. /// /// Val: 6-digit hex RGB string WITHOUT the "#" prefix (e.g., "FF0000" for red). /// The special value "auto" means the application decides (usually black). /// /// /// ThemeColor: References a theme color slot. When set alongside Val, the /// theme color takes precedence in theme-aware applications, but Val is the fallback. /// /// /// ThemeShade: Darkens the theme color. Value is a 2-digit hex string (00–FF). /// 00 = no change, FF = fully darkened. Applied as a multiplier. /// /// /// ThemeTint: Lightens the theme color. Value is a 2-digit hex string (00–FF). /// 00 = no change, FF = fully lightened (white). Applied as a multiplier. /// /// /// Gotcha: ThemeShade and ThemeTint are mutually exclusive — only one should /// be set. If both are present, behavior is undefined. /// /// public static void ApplyColor(Run run) { var rPr = run.GetOrCreateRunProperties(); // Simple hex color (no theme) rPr.Color = new Color { Val = "FF0000" }; // Red // Theme-based color with fallback hex value rPr.Color = new Color { Val = "2F5496", // Fallback hex for non-theme-aware renderers ThemeColor = ThemeColorValues.Accent1, // Theme color slot ThemeTint = "99" // Lighten: 99 hex → ~60% tint }; // Theme color darkened rPr.Color = new Color { Val = "1F3864", ThemeColor = ThemeColorValues.Accent1, ThemeShade = "BF" // Darken: BF hex → ~75% shade }; // Auto color (application-determined, typically black on white) rPr.Color = new Color { Val = "auto" }; } // ────────────────────────────────────────────────────────────────── // 6. Highlight (w:highlight) // ────────────────────────────────────────────────────────────────── /// /// Applies text highlighting (the "marker pen" effect in Word's UI). /// /// All HighlightColorValues: Yellow, Green, Cyan, Magenta, Blue, Red, /// DarkBlue, DarkCyan, DarkGreen, DarkMagenta, DarkRed, DarkYellow, /// DarkGray, LightGray, Black, White, None. /// /// /// Gotcha: Highlighting is limited to the 17 preset colors above. /// For arbitrary background colors, use on RunProperties /// instead — it supports any hex color. /// /// public static void ApplyHighlight(Run run) { var rPr = run.GetOrCreateRunProperties(); // Standard yellow highlight (most common for "tracked" or "review" marks) rPr.Highlight = new Highlight { Val = HighlightColorValues.Yellow }; // All available highlight colors for reference: // rPr.Highlight = new Highlight { Val = HighlightColorValues.Green }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.Cyan }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.Magenta }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.Blue }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.Red }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.DarkBlue }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.DarkCyan }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.DarkGreen }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.DarkMagenta }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.DarkRed }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.DarkYellow }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.DarkGray }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.LightGray }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.Black }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.White }; // rPr.Highlight = new Highlight { Val = HighlightColorValues.None }; // Remove } // ────────────────────────────────────────────────────────────────── // 7. Strikethrough (w:strike, w:dstrike) // ────────────────────────────────────────────────────────────────── /// /// Applies strikethrough or double-strikethrough formatting. /// /// Gotcha: w:strike and w:dstrike are mutually exclusive. /// If both are present, behavior is undefined (Word typically uses the last one set). /// /// public static void ApplyStrikethrough(Run run) { var rPr = run.GetOrCreateRunProperties(); // Single strikethrough: a single horizontal line through the text rPr.Strike = new Strike(); // No Val = true // Double strikethrough: two horizontal lines through the text // rPr.DoubleStrike = new DoubleStrike(); // To explicitly disable (override a style that has strikethrough): // rPr.Strike = new Strike { Val = false }; } // ────────────────────────────────────────────────────────────────── // 8. Superscript / Subscript (w:vertAlign) // ────────────────────────────────────────────────────────────────── /// /// Applies superscript or subscript vertical alignment. /// /// Values: /// /// Superscript — raised text, reduced size (e.g., x²) /// Subscript — lowered text, reduced size (e.g., H₂O) /// Baseline — normal position (use to override style) /// /// /// /// Gotcha: This is NOT the same as . /// VerticalTextAlignment changes both position AND size (like Word's superscript button). /// Position (w:position) only shifts the baseline without changing font size. /// /// public static void ApplySuperSubscript(Run run) { var rPr = run.GetOrCreateRunProperties(); // Superscript (raised + smaller font) rPr.VerticalTextAlignment = new VerticalTextAlignment { Val = VerticalPositionValues.Superscript }; // Subscript (lowered + smaller font) // rPr.VerticalTextAlignment = new VerticalTextAlignment // { // Val = VerticalPositionValues.Subscript // }; // Baseline — explicitly reset to normal (override a style) // rPr.VerticalTextAlignment = new VerticalTextAlignment // { // Val = VerticalPositionValues.Baseline // }; } // ────────────────────────────────────────────────────────────────── // 9. Caps / Small Caps (w:caps, w:smallCaps) // ────────────────────────────────────────────────────────────────── /// /// Applies ALL CAPS or Small Caps display formatting. /// /// Caps (w:caps): Displays all characters as uppercase. The underlying text /// is NOT modified — it remains lowercase in the XML. This is a display-only transform. /// /// /// SmallCaps (w:smallCaps): Displays lowercase letters as smaller uppercase /// glyphs. Original uppercase letters remain full size. Common in legal and academic /// documents for author names and section references. /// /// /// Gotcha: w:caps and w:smallCaps are mutually exclusive. /// If both are present, w:caps wins. /// /// public static void ApplyCapsSmallCaps(Run run) { var rPr = run.GetOrCreateRunProperties(); // ALL CAPS display (text stored as-is, displayed uppercase) rPr.Caps = new Caps(); // Small Caps display (lowercase → small uppercase glyphs) // rPr.SmallCaps = new SmallCaps(); // Disable (override a style): // rPr.Caps = new Caps { Val = false }; } // ────────────────────────────────────────────────────────────────── // 10. Character Spacing (w:spacing) // ────────────────────────────────────────────────────────────────── /// /// Adjusts the spacing between characters (tracking / character spacing). /// /// Unit: Value is in twips (1/20 of a point). /// Positive values = expanded (letters spread apart). /// Negative values = condensed (letters squeezed together). /// /// /// Examples: 20 twips = 1pt expanded, -10 twips = 0.5pt condensed, /// 40 twips = 2pt expanded. /// /// /// Gotcha: This is NOT the same as kerning (w:kern). /// Spacing applies a uniform offset between ALL characters. /// Kerning adjusts spacing between specific character PAIRS based on font metrics. /// /// public static void ApplyCharacterSpacing(Run run) { var rPr = run.GetOrCreateRunProperties(); // Expanded by 1pt (20 twips) rPr.Spacing = new Spacing { Val = 20 }; // Condensed by 0.5pt (-10 twips) // rPr.Spacing = new Spacing { Val = -10 }; } // ────────────────────────────────────────────────────────────────── // 11. Position — raised/lowered baseline (w:position) // ────────────────────────────────────────────────────────────────── /// /// Raises or lowers the text position relative to the baseline. /// /// Unit: Value is in half-points. /// Positive values = raised above baseline. /// Negative values = lowered below baseline. /// /// /// Examples: 6 half-points = 3pt raised, -4 half-points = 2pt lowered. /// /// /// Gotcha: Unlike , Position does NOT change /// the font size. It only shifts the vertical position. Use this for fine-tuning /// baseline alignment (e.g., aligning inline images with text). /// /// public static void ApplyPosition(Run run) { var rPr = run.GetOrCreateRunProperties(); // Raise text by 3pt (6 half-points) rPr.Position = new Position { Val = "6" }; // Lower text by 2pt (-4 half-points) // rPr.Position = new Position { Val = "-4" }; } // ────────────────────────────────────────────────────────────────── // 12. Run Shading (w:shd) — arbitrary background color on text // ────────────────────────────────────────────────────────────────── /// /// Applies shading (background color) to a run. /// /// Use case: When you need a background color that is NOT one of the 17 /// preset highlight colors. Shading supports any hex RGB value. /// /// /// Fill: The background color (hex RGB, e.g., "FFFF00" for yellow). /// Val: The shading pattern. Use ShadingPatternValues.Clear for a /// solid background fill (most common). Other patterns overlay a foreground color. /// Color: The foreground/pattern color (only meaningful for non-Clear patterns). /// /// /// Gotcha: If Val is omitted or set to Nil, the shading may not render. /// Always set Val = Clear for solid backgrounds. /// /// public static void ApplyShading(Run run) { var rPr = run.GetOrCreateRunProperties(); // Solid light-blue background rPr.Shading = new Shading { Val = ShadingPatternValues.Clear, // Solid fill (no pattern) Fill = "DAEEF3", // Background color: light blue Color = "auto" // Foreground/pattern color: auto }; // Theme-colored shading // rPr.Shading = new Shading // { // Val = ShadingPatternValues.Clear, // Fill = "auto", // ThemeFill = ThemeColorValues.Accent1, // ThemeFillTint = "33" // Light tint of accent1 // }; } // ────────────────────────────────────────────────────────────────── // 13. Text Border (w:bdr) // ────────────────────────────────────────────────────────────────── /// /// Applies a border around a run of text. /// /// Val: Border style — Single, Double, Dotted, Dashed, DotDash, DotDotDash, /// Triple, ThickThinSmallGap, ThinThickSmallGap, ThickThinMediumGap, etc. /// Use BorderValues.None to remove. /// /// /// Size: Border width in eighths of a point. 4 = 0.5pt, 8 = 1pt, 12 = 1.5pt. /// Valid range: 2–96 (0.25pt–12pt). /// /// /// Space: Padding between text and border in points. Range: 0–31. /// /// /// Gotcha: Run borders look like "boxed text" in Word. Adjacent runs with /// borders will have separate boxes — they do NOT merge into one box. /// /// public static void ApplyBorder(Run run) { var rPr = run.GetOrCreateRunProperties(); rPr.Border = new Border { Val = BorderValues.Single, // Single-line border Size = 4, // 0.5pt wide (4 eighths of a point) Space = 1, // 1pt padding between text and border Color = "4472C4" // Border color (blue) }; // Double border // rPr.Border = new Border // { // Val = BorderValues.Double, // Size = 4, // Space = 1, // Color = "auto" // }; // Theme-colored border // rPr.Border = new Border // { // Val = BorderValues.Single, // Size = 8, // Space = 1, // Color = "auto", // ThemeColor = ThemeColorValues.Accent1 // }; } // ────────────────────────────────────────────────────────────────── // 14. Run Style Reference (w:rStyle) // ────────────────────────────────────────────────────────────────── /// /// Applies a named character style to a run. /// /// Val: The style ID (not the display name). For example, Word's built-in /// "Strong" style has ID "Strong", "Emphasis" has ID "Emphasis". /// Custom styles use their internal ID which may differ from the display name. /// /// /// Gotcha: The style must exist in the document's styles.xml (StyleDefinitionsPart). /// Referencing a non-existent style ID will not cause an error, but the formatting /// defined by that style will not be applied — Word silently ignores unknown style IDs. /// /// /// Gotcha: RunProperties set directly on the run override properties from the /// style (direct formatting wins). To inherit everything from the style, do not set /// additional properties on the RunProperties. /// /// public static void ApplyRunStyle(Run run) { var rPr = run.GetOrCreateRunProperties(); // Reference the built-in "Strong" character style (bold) rPr.RunStyle = new RunStyle { Val = "Strong" }; // Common built-in character style IDs: // "Strong" — Bold // "Emphasis" — Italic // "IntenseEmphasis" — Bold + Italic + Accent color // "SubtleEmphasis" — Italic + gray color // "BookTitle" — Small caps + spacing // "IntenseReference" — Bold + Small caps + Accent color + Underline // "SubtleReference" — Small caps + Accent color // "Hyperlink" — Blue + Underline // "FollowedHyperlink" — Purple + Underline // "FootnoteReference" — Superscript } // ────────────────────────────────────────────────────────────────── // 15. Hidden Text (w:vanish) // ────────────────────────────────────────────────────────────────── /// /// Makes text hidden (invisible in normal view, shown with dotted underline /// when "Show/Hide" is toggled in Word). /// /// Use cases: Hidden text for internal notes, index entries, TOC field codes. /// Hidden text is NOT printed by default (controlled by Word's print settings). /// /// /// Gotcha: Hidden text still participates in page layout calculations in some /// modes. It can affect pagination when revealed. /// /// public static void ApplyHiddenText(Run run) { var rPr = run.GetOrCreateRunProperties(); // Make text hidden rPr.Vanish = new Vanish(); // Explicitly un-hide (override a style that hides text): // rPr.Vanish = new Vanish { Val = false }; } // ────────────────────────────────────────────────────────────────── // 16. Right-to-Left / Complex Script (w:rtl, w:cs) // ────────────────────────────────────────────────────────────────── /// /// Marks a run as right-to-left and/or complex script. /// /// RightToLeft (w:rtl): Indicates the run contains right-to-left text. /// This affects character ordering and cursor movement. Required for Arabic/Hebrew text. /// /// /// ComplexScript (w:cs): Marks the run as containing complex script text. /// When set, Word uses the ComplexScript variants of font properties: /// w:szCs instead of w:sz, w:bCs instead of w:b, rFonts@cs instead of rFonts@ascii. /// /// /// Gotcha: For Arabic/Hebrew content, you typically need BOTH w:rtl and w:cs. /// Thai text needs w:cs but NOT w:rtl (Thai is left-to-right but uses complex shaping). /// /// public static void ApplyRightToLeft(Run run) { var rPr = run.GetOrCreateRunProperties(); // Mark as right-to-left (for Arabic/Hebrew) rPr.RightToLeftText = new RightToLeftText(); // Mark as complex script (use CS font/size/bold/italic variants) rPr.ComplexScript = new ComplexScript(); } // ────────────────────────────────────────────────────────────────── // 17. Emphasis Mark (w:em) — CJK emphasis dots // ────────────────────────────────────────────────────────────────── /// /// Applies emphasis marks (dots/circles above or below characters). /// Primarily used in CJK (Chinese, Japanese, Korean) typography. /// /// Values: /// /// Dot — small filled dot above each character (Japanese: 傍点) /// Comma — small comma-like mark above (used in some CJK styles) /// Circle — small open circle above each character /// UnderDot — small filled dot below each character (Chinese style) /// None — remove emphasis marks /// /// /// /// Gotcha: Emphasis marks are distinct from underlines. They appear as individual /// marks above/below each character, not as a continuous line. /// /// public static void ApplyEmphasisMark(Run run) { var rPr = run.GetOrCreateRunProperties(); // Dot emphasis (most common in Japanese) rPr.Emphasis = new Emphasis { Val = EmphasisMarkValues.Dot }; // Other emphasis mark styles: // rPr.Emphasis = new Emphasis { Val = EmphasisMarkValues.Comma }; // rPr.Emphasis = new Emphasis { Val = EmphasisMarkValues.Circle }; // rPr.Emphasis = new Emphasis { Val = EmphasisMarkValues.UnderDot }; // rPr.Emphasis = new Emphasis { Val = EmphasisMarkValues.None }; } // ────────────────────────────────────────────────────────────────── // 18. Kerning (w:kern) // ────────────────────────────────────────────────────────────────── /// /// Sets the kerning threshold for automatic font-based kerning. /// /// Unit: Value is in half-points. Characters at or above this size /// will have kerning applied (the font's kern table adjusts spacing between /// specific character pairs, e.g., "AV", "To", "WA"). /// /// /// Common values: /// /// 0 — Disable kerning entirely /// 2 (1pt) — Kern all text (including body text) /// 28 (14pt) — Kern only headings (Word's typical default threshold) /// /// /// /// Gotcha: Kerning only works if the font contains a kern table. /// Most professional fonts (Times New Roman, Calibri, Arial) include kern data. /// /// public static void ApplyKerning(Run run) { var rPr = run.GetOrCreateRunProperties(); // Kern text at 14pt and above (28 half-points) rPr.Kern = new Kern { Val = 28 }; // Kern all text regardless of size (0 half-points is "no threshold" // but some renderers interpret 0 as "off". Use 1 or 2 to be safe.) // rPr.Kern = new Kern { Val = 2 }; } // ────────────────────────────────────────────────────────────────── // 19. Fully Formatted Run (combining multiple properties) // ────────────────────────────────────────────────────────────────── /// /// Creates a fully formatted run combining multiple character properties. /// Demonstrates the correct way to build a run with RunProperties. /// /// Key principle: Create RunProperties first, add all child elements, /// then set it on the run BEFORE adding text. The run's XML structure must be: /// <w:r><w:rPr>...</w:rPr><w:t>text</w:t></w:r> /// /// /// Gotcha: If you add RunProperties AFTER the Text element, it will appear /// after w:t in the XML, which is technically invalid OOXML ordering. Word tolerates /// it but some third-party parsers may not. Always add rPr first. /// /// public static Run CreateFullyFormattedRun() { // Build RunProperties with all desired formatting var rPr = new RunProperties(); // 1. Style reference (must be first child per schema order) rPr.RunStyle = new RunStyle { Val = "Strong" }; // 2. Font family rPr.RunFonts = new RunFonts { Ascii = "Georgia", HighAnsi = "Georgia", EastAsia = "SimSun", ComplexScript = "Times New Roman" }; // 3. Bold rPr.Bold = new Bold(); rPr.BoldComplexScript = new BoldComplexScript(); // 4. Italic rPr.Italic = new Italic(); rPr.ItalicComplexScript = new ItalicComplexScript(); // 5. Caps — omitted here (mutually exclusive with SmallCaps) // rPr.Caps = new Caps(); // 6. SmallCaps rPr.SmallCaps = new SmallCaps(); // 7. Strikethrough rPr.Strike = new Strike(); // 8. Hidden — typically NOT combined with visible formatting // rPr.Vanish = new Vanish(); // 9. Color rPr.Color = new Color { Val = "2F5496" }; // 10. Font size rPr.FontSize = new FontSize { Val = "28" }; // 14pt rPr.FontSizeComplexScript = new FontSizeComplexScript { Val = "28" }; // 11. Underline rPr.Underline = new Underline { Val = UnderlineValues.Single }; // 12. Shading (text background) rPr.Shading = new Shading { Val = ShadingPatternValues.Clear, Fill = "FFFFCC" }; // 13. Highlight (preset colors only) // rPr.Highlight = new Highlight { Val = HighlightColorValues.Yellow }; // 14. Character spacing rPr.Spacing = new Spacing { Val = 10 }; // 0.5pt expanded // 15. Kerning threshold rPr.Kern = new Kern { Val = 2 }; // 16. Position (raised/lowered) // rPr.Position = new Position { Val = "4" }; // 2pt raised // 17. Vertical alignment (super/subscript) // rPr.VerticalTextAlignment = new VerticalTextAlignment // { // Val = VerticalPositionValues.Superscript // }; // 18. Border rPr.Border = new Border { Val = BorderValues.Single, Size = 4, Space = 1, Color = "auto" }; // Build the Run: RunProperties MUST come before Text content var run = new Run(); run.RunProperties = rPr; // Add text content // PreserveSpace is needed when text has leading/trailing spaces run.AppendChild(new Text("Fully formatted text") { Space = SpaceProcessingModeValues.Preserve }); return run; } // ────────────────────────────────────────────────────────────────── // 20. BuildRunProperties helper — recommended property order // ────────────────────────────────────────────────────────────────── /// /// Helper that constructs a RunProperties with elements in the correct schema order. /// /// OOXML schema order for w:rPr children (ISO 29500-1, section 17.3.2.28): /// /// w:rStyle — Character style reference /// w:rFonts — Font family /// w:b — Bold /// w:bCs — Bold Complex Script /// w:i — Italic /// w:iCs — Italic Complex Script /// w:caps — All Caps /// w:smallCaps — Small Caps /// w:strike — Strikethrough /// w:dstrike — Double Strikethrough /// w:outline — Outline effect /// w:shadow — Shadow effect /// w:emboss — Emboss effect /// w:imprint — Imprint/Engrave effect /// w:noProof — Skip proofing /// w:snapToGrid — Snap to document grid /// w:vanish — Hidden text /// w:webHidden — Hidden in web view /// w:color — Text color /// w:spacing — Character spacing /// w:w — Character width scaling (%) /// w:kern — Kerning threshold /// w:position — Raised/lowered position /// w:sz — Font size /// w:szCs — Font size Complex Script /// w:highlight — Highlight color /// w:u — Underline /// w:effect — Animation effect (deprecated) /// w:bdr — Text border /// w:shd — Shading /// w:fitText — Fit text to width /// w:vertAlign — Vertical alignment (super/subscript) /// w:rtl — Right-to-left /// w:cs — Complex Script /// w:em — Emphasis mark /// w:lang — Language /// w:eastAsianLayout — East Asian typography /// w:specVanish — Special vanish /// w:oMath — Math formatting /// w:rPrChange — Revision tracking for run properties /// /// /// /// Gotcha: When using the strongly-typed SDK (setting properties like /// rPr.Bold = new Bold()), the SDK handles ordering automatically when /// serializing. However, if you use rPr.AppendChild(), you must add /// elements in the correct order yourself, or call /// rPr.SetElement() which inserts at the correct position. /// /// /// Font name for Ascii and HighAnsi slots. Null to skip. /// Font size in points. Null to skip. /// True to apply bold, false to explicitly disable, null to inherit. /// True to apply italic, false to explicitly disable, null to inherit. /// Six-digit hex color (e.g., "FF0000"). Null to skip. /// Underline style. Null to skip. /// A well-ordered RunProperties element ready to attach to a Run. public static RunProperties BuildRunProperties( string? fontFamily = null, double? sizePoints = null, bool? bold = null, bool? italic = null, string? colorHex = null, UnderlineValues? underline = null) { var rPr = new RunProperties(); // Using the strongly-typed properties ensures the SDK serializes // child elements in the correct schema order automatically. if (fontFamily is not null) { rPr.RunFonts = new RunFonts { Ascii = fontFamily, HighAnsi = fontFamily }; } if (bold == true) { rPr.Bold = new Bold(); rPr.BoldComplexScript = new BoldComplexScript(); } else if (bold == false) { rPr.Bold = new Bold { Val = false }; rPr.BoldComplexScript = new BoldComplexScript { Val = false }; } if (italic == true) { rPr.Italic = new Italic(); rPr.ItalicComplexScript = new ItalicComplexScript(); } else if (italic == false) { rPr.Italic = new Italic { Val = false }; rPr.ItalicComplexScript = new ItalicComplexScript { Val = false }; } if (colorHex is not null) { rPr.Color = new Color { Val = colorHex }; } if (sizePoints is not null) { var halfPts = ((int)(sizePoints.Value * 2)).ToString(); rPr.FontSize = new FontSize { Val = halfPts }; rPr.FontSizeComplexScript = new FontSizeComplexScript { Val = halfPts }; } if (underline is not null) { rPr.Underline = new Underline { Val = underline }; } return rPr; } // ────────────────────────────────────────────────────────────────── // Internal helper: get or create RunProperties on a Run // ────────────────────────────────────────────────────────────────── /// /// Gets the existing RunProperties from a run or creates and attaches a new one. /// Ensures RunProperties is always the first child element of the run. /// private static RunProperties GetOrCreateRunProperties(this Run run) { if (run.RunProperties is not null) return run.RunProperties; var rPr = new RunProperties(); run.RunProperties = rPr; return rPr; } }