Working in Code
Scryber supports a full object model, so you can build, inspect, and modify documents directly in C# without relying only on template markup.
This is often most useful when you need:
- dynamic structure generation at runtime
- shared document composition logic across many templates
- strongly typed style and layout values
- central control of rendering behavior
Common Namespaces
using Scryber;
using Scryber.Components;
using Scryber.Drawing;
using Scryber.Styles;
Build a Document in Code
You can construct components directly and add them to the content tree.
using Scryber;
using Scryber.Components;
using Scryber.Drawing;
var doc = new Document();
var page = new Page();
var section = new Section();
var title = new Label();
title.Text = "Runtime Report";
title.Style.Font.FontSize = 24;
title.Style.Font.FontBold = true;
title.Style.Margins.Bottom = 10;
var body = new Div();
body.Style.Padding.All = 12;
body.Style.Border.Width = 1;
body.Style.Border.Color = StandardColors.Gray;
body.Contents.Add(new TextLiteral("Generated entirely in code."));
section.Contents.Add(title);
section.Contents.Add(body);
page.Contents.Add(section);
doc.Pages.Add(page);
doc.SaveAsPDF("working-in-code.pdf");
Build XHTML in Code and Parse a Component
If part of your document is easier to generate as markup, you can build an XHTML fragment and parse it into a component.
using System.IO;
using System.Text;
using Scryber;
using Scryber.Components;
var xhtml = new StringBuilder()
.AppendLine("<div xmlns='http://www.w3.org/1999/xhtml' id='runtime-card' class='card'>")
.AppendLine(" <h2>Summary</h2>")
.AppendLine(" <p>This section was generated from an XHTML string.</p>")
.AppendLine("</div>")
.ToString();
var parsed = Document.ParseComponent(new StringReader(xhtml), ParseSourceType.Template);
var doc = new Document();
var page = new Page();
var section = new Section();
if (parsed is Div card)
{
section.Contents.Add(card);
}
page.Contents.Add(section);
doc.Pages.Add(page);
doc.SaveAsPDF("component-from-xhtml.pdf");
Use ParseSourceType.Template for fragments (single component trees) and include the XHTML namespace on the fragment root.
Working with Styles in Code
Most Style values can be set directly on the component properties
var card = new Panel()
{
Width = 320,
Height = 180,
Padding = new Thickness(12),
Margins = new Thickness(0, 0, 10, 0),
BackgroundColor = Color.Parse("#f6f8fb"),
BorderWidth = 1,
BorderColor = new Color(210, 218, 230),
BorderCornerRadius = 8,
FontFamily = new FontSelector("Helvetica"),
FontSize = 11,
};
Or map naturally to typed properties:
var card = new Panel();
card.Style.Size.Width = 320;
card.Style.Size.Height = 180;
card.Style.Padding.All = 12;
card.Style.Margins.Bottom = 10;
card.Style.Background.Color = Color.Parse("#f6f8fb");
card.Style.Border.Width = 1;
card.Style.Border.Color = new Color(210, 218, 230);
card.Style.Border.CornerRadius = 8;
card.Style.Font.FontFamily = "Helvetica";
card.Style.Font.FontSize = 11;
Value Types (Unit, Thickness, Color)
Unit
Unit represents CSS-like measurement values (pt, mm, in, %, em, etc.).
Unit w1 = 120; // points
Unit w2 = new Unit(25, PageUnits.Millimeters);
Unit w3 = Unit.Parse("75%");
Unit w4 = Unit.Parse("12pt");
component.Style.Size.Width = w2;
component.Style.Size.MaxWidth = w3;
Thickness
Thickness represents 1/2/4-edge values (top, right, bottom, left).
var all = new Thickness(8); // all edges
var verticalHorizontal = Thickness.Parse("12pt 18pt"); // TB RL
var eachEdge = new Thickness(10, 20, 10, 20); // T R B L
component.Style.Padding = all;
component.Style.Margins = verticalHorizontal;
component.Style.Border.Dash.Offset = 0; // normal property still typed
Color
Color supports named values, hex, rgb(...), cmyk(...), and constants via StandardColors.
component.Style.Fill.Color = StandardColors.Blue;
component.Style.Background.Color = Color.Parse("#1f2937");
component.Style.Border.Color = new Color(34, 139, 34); // RGB
component.Style.Outline.Color = Color.Parse("cmyk(0,100,100,0)");
Parsing CSS-Like Values from Strings
When values come from configuration or data, parse to strongly typed values:
if (Unit.TryParse(input.Width, out var width))
component.Style.Size.Width = width;
if (Thickness.TryParse(input.Padding, out var padding))
component.Style.Padding = padding;
if (Color.TryParse(input.AccentColor, out var accent))
component.Style.Border.Color = accent;
This is useful for admin-configured themes or per-tenant branding.
Mixing Templates and Code
A common pattern is:
- Parse template
- Find key components by ID / outlet
- Apply runtime logic and typed styles
- Render PDF
var doc = Document.ParseDocument("invoice.html");
if (doc.TryFindComponentById("StatusBadge", out IComponent found) && found is Label badge)
{
badge.Text = "PAID";
badge.Style.Background.Color = StandardColors.Green;
badge.Style.Fill.Color = StandardColors.White;
badge.Style.Padding = new Thickness(4, 8, 4, 8);
}
doc.SaveAsPDF("invoice.pdf");
Helpful Patterns
- Prefer typed values (
Unit,Thickness,Color) over raw strings when writing code. - Use
TryParse(...)for user/data-driven values to avoid runtime failures. - Keep controller actions focused and extract reusable style-building methods.
- Use
StandardColorsfor common colors, andnew Color(r,g,b)orColor.Parse(...)for configurable values. - Style property value types are generally in the
Scryber.Drawingnamespace - Unit, Point, Rect, Thickness, Color, Gradient etc. - Use outlets/controllers for known template anchors; use DOM search for cross-template transforms.