Data Binding Basics
Learn the fundamentals of data binding to create dynamic, data-driven PDF documents.
Learning Objectives
By the end of this article, you’ll be able to:
- Understand the `` syntax
- Bind data to templates
- Access object properties and nested data
- Pass data from C# to templates
- Use different data sources (C# objects, JSON, XML)
What is Data Binding?
Data binding connects your data to template placeholders, allowing you to generate dynamic content:
Static Template:
<p>Hello, World!</p>
Dynamic Template with Data Binding:
<p>Hello, {{model.name}}!</p>
With Data:
doc.Params["model"] = new { name = "John" };
Result:
<p>Hello, John!</p>
Basic Syntax
Single Value Binding
<!-- Simple property -->
<p>{{name}}</p>
<!-- Object property -->
<p>{{user.name}}</p>
<!-- Nested property -->
<p>{{user.address.city}}</p>
Multiple Bindings
<h1>{{title}}</h1>
<p>Author: {{author}}</p>
<p>Date: {{date}}</p>
<p>{{content}}</p>
Passing Data from C#
Using Anonymous Objects
var doc = Document.ParseDocument("template.html");
// Pass data
doc.Params["model"] = new
{
name = "John Doe",
email = "john@example.com",
age = 30
};
doc.SaveAsPDF("output.pdf");
Template:
<h1>{{model.name}}</h1>
<p>Email: {{model.email}}</p>
<p>Age: {{model.age}}</p>
Using Typed Objects
public class Person
{
public string Name { get; set; }
public string Email { get; set; }
public int Age { get; set; }
}
// Usage
var person = new Person
{
Name = "John Doe",
Email = "john@example.com",
Age = 30
};
doc.Params["model"] = person;
Using Collections
var users = new[]
{
new { name = "Alice", role = "Admin" },
new { name = "Bob", role = "User" },
new { name = "Charlie", role = "Guest" }
};
doc.Params["users"] = users;
{{#each users}}
<p>{{this.name}} - {{this.role}}</p>
{{/each}}
Accessing Properties
Simple Properties
<p>{{firstName}}</p>
<p>{{lastName}}</p>
<p>{{age}}</p>
doc.Params["firstName"] = "John";
doc.Params["lastName"] = "Doe";
doc.Params["age"] = 30;
Object Properties
<p>{{customer.name}}</p>
<p>{{customer.email}}</p>
<p>{{customer.phone}}</p>
doc.Params["customer"] = new
{
name = "John Doe",
email = "john@example.com",
phone = "555-1234"
};
Nested Properties
<p>{{user.profile.firstName}}</p>
<p>{{user.profile.lastName}}</p>
<p>{{user.address.street}}</p>
<p>{{user.address.city}}, {{user.address.state}}</p>
doc.Params["user"] = new
{
profile = new
{
firstName = "John",
lastName = "Doe"
},
address = new
{
street = "123 Main St",
city = "Springfield",
state = "IL"
}
};
Complete Examples
Example 1: Simple Business Card
C# Code:
var doc = Document.ParseDocument("business-card.html");
doc.Params["model"] = new
{
name = "John Doe",
title = "Software Engineer",
company = "Tech Corp",
email = "john@techcorp.com",
phone = "(555) 123-4567"
};
doc.SaveAsPDF("business-card.pdf");
Template (business-card.html):
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<title>Business Card</title>
<style>
body {
font-family: Helvetica, sans-serif;
padding: 40pt;
}
.card {
border: 2pt solid #2563eb;
padding: 30pt;
width: 400pt;
}
.name {
font-size: 24pt;
font-weight: bold;
color: #1e40af;
}
.title {
font-size: 14pt;
color: #666;
margin-bottom: 10pt;
}
.company {
font-size: 16pt;
font-weight: 600;
margin-bottom: 20pt;
}
.contact {
font-size: 10pt;
}
</style>
</head>
<body>
<div class="card">
<div class="name">{{model.name}}</div>
<div class="title">{{model.title}}</div>
<div class="company">{{model.company}}</div>
<div class="contact">
<p>{{model.email}}</p>
<p>{{model.phone}}</p>
</div>
</div>
</body>
</html>
Example 2: Simple Invoice
C# Code:
var doc = Document.ParseDocument("invoice.html");
doc.Params["model"] = new
{
invoiceNumber = "INV-2025-001",
date = "2025-01-15",
customerName = "Acme Corporation",
items = new[]
{
new { description = "Consulting Services", hours = 10, rate = 150.00, total = 1500.00 },
new { description = "Software Development", hours = 20, rate = 200.00, total = 4000.00 }
},
subtotal = 5500.00,
tax = 440.00,
total = 5940.00
};
doc.SaveAsPDF("invoice.pdf");
Template (invoice.html):
<!DOCTYPE html>
<html xmlns='http://www.w3.org/1999/xhtml'>
<head>
<title>Invoice</title>
<style>
body {
font-family: Helvetica, sans-serif;
margin: 40pt;
}
h1 {
color: #1e40af;
border-bottom: 2pt solid #1e40af;
padding-bottom: 10pt;
}
.invoice-header {
margin-bottom: 30pt;
}
.invoice-info {
font-size: 10pt;
color: #666;
}
table {
width: 100%;
border-collapse: collapse;
margin: 20pt 0;
}
th {
background-color: #2563eb;
color: white;
padding: 10pt;
text-align: left;
}
td {
padding: 8pt;
border-bottom: 1pt solid #e5e7eb;
}
.total-row {
background-color: #eff6ff;
font-weight: bold;
font-size: 14pt;
}
</style>
</head>
<body>
<div class="invoice-header">
<h1>INVOICE</h1>
<div class="invoice-info">
<p>Invoice #: {{model.invoiceNumber}}</p>
<p>Date: {{model.date}}</p>
<p>Customer: {{model.customerName}}</p>
</div>
</div>
<table>
<thead>
<tr>
<th>Description</th>
<th>Hours</th>
<th>Rate</th>
<th style="text-align: right;">Total</th>
</tr>
</thead>
<tbody>
{{#each model.items}}
<tr>
<td>{{this.description}}</td>
<td>{{this.hours}}</td>
<td>${{this.rate}}</td>
<td style="text-align: right;">${{this.total}}</td>
</tr>
{{/each}}
</tbody>
<tfoot>
<tr>
<td colspan="3">Subtotal</td>
<td style="text-align: right;">${{model.subtotal}}</td>
</tr>
<tr>
<td colspan="3">Tax (8%)</td>
<td style="text-align: right;">${{model.tax}}</td>
</tr>
<tr class="total-row">
<td colspan="3">TOTAL</td>
<td style="text-align: right;">${{model.total}}</td>
</tr>
</tfoot>
</table>
</body>
</html>
Working with JSON Data
Load JSON from File
string jsonContent = File.ReadAllText("data.json");
var data = JsonSerializer.Deserialize<dynamic>(jsonContent);
doc.Params["model"] = data;
data.json:
{
"title": "Monthly Report",
"author": "John Doe",
"date": "2025-01-15",
"sections": [
{
"heading": "Introduction",
"content": "This is the introduction..."
},
{
"heading": "Analysis",
"content": "Detailed analysis..."
}
]
}
Load JSON from API
using System.Net.Http;
using System.Text.Json;
public async Task<byte[]> GenerateReportFromApi(string apiUrl)
{
using var client = new HttpClient();
string jsonResponse = await client.GetStringAsync(apiUrl);
var data = JsonSerializer.Deserialize<dynamic>(jsonResponse);
var doc = Document.ParseDocument("report.html");
doc.Params["model"] = data;
using (var ms = new MemoryStream())
{
doc.SaveAsPDF(ms);
return ms.ToArray();
}
}
Working with XML Data
using System.Xml.Linq;
// Load XML
var xml = XDocument.Load("data.xml");
// Convert to anonymous object
var data = new
{
title = xml.Root.Element("title")?.Value,
author = xml.Root.Element("author")?.Value,
sections = xml.Root.Elements("section").Select(s => new
{
heading = s.Element("heading")?.Value,
content = s.Element("content")?.Value
}).ToArray()
};
doc.Params["model"] = data;
data.xml:
<?xml version="1.0"?>
<report>
<title>Monthly Report</title>
<author>John Doe</author>
<section>
<heading>Introduction</heading>
<content>This is the introduction...</content>
</section>
<section>
<heading>Analysis</heading>
<content>Detailed analysis...</content>
</section>
</report>
Null and Missing Values
Handling Null Values
<!-- If property is null, nothing is rendered -->
<p>{{model.optionalField}}</p>
<!-- Use default values -->
<p>{{model.optionalField ?? 'Not provided'}}</p>
<!-- Conditional display -->
{{#if model.optionalField}}
<p>{{model.optionalField}}</p>
{{else}}
<p>Not available</p>
{{/if}}
Safe Navigation
// Avoid null reference errors
doc.Params["model"] = new
{
user = null // Or any property could be null
};
// Safe in template if user is null - just shows nothing
//
Try It Yourself
Exercise 1: Personal Letter
Create a template for a personal letter with:
- Recipient name and address
- Letter date
- Greeting with name
- Custom message body
- Signature
Generate PDFs for 3 different people.
Exercise 2: Product List
Create a template that displays:
- Company name and logo path
- List of products with names and prices
- Total count of products
Pass an array of products from C#.
Exercise 3: JSON to PDF
- Create a JSON file with your resume data
- Create a template that formats it nicely
- Load JSON and generate PDF
Common Pitfalls
❌ Wrong Property Names
<!-- Template uses: {{model.Name}} -->
<p>{{model.Name}}</p>
// But C# property is: name (lowercase)
doc.Params["model"] = new { name = "John" };
// Won't bind! Property names are case-sensitive
✅ Solution: Match case exactly
doc.Params["model"] = new { Name = "John" };
❌ Forgetting to Pass Data
<p>{{model.name}}</p>
var doc = Document.ParseDocument("template.html");
// Forgot: doc.Params["model"] = data;
doc.SaveAsPDF("output.pdf");
// Shows: literally in PDF
✅ Solution: Always pass data
doc.Params["model"] = data;
❌ Using Wrong Context Name
<p>{{user.name}}</p>
// But passed as "model"
doc.Params["model"] = new { name = "John" };
✅ Solution: Match context names
doc.Params["user"] = new { name = "John" };
Next Steps
Now that you understand data binding basics:
- Expression Functions - Use functions in expressions
- Template Iteration - Loop through collections
- Conditional Rendering - Show/hide content
Continue learning → Expression Functions