Merge Fields
A merge field looks like a simple placeholder, but it carries rules of its own: a number or date format, text before and after the value, the case of its letters. Beyond the basics, you apply these rules to all fields of a template, insert date fields, handle fields without data, replace the merged content in code and decide how form fields receive their values.
Field names, inserting fields in the Document Editor, MS Word and code and handling missing data are the subjects of Merge Fields in Getting Started. IF fields are covered in Conditional Content. The programs work with the files template.docx and data.json of Simple Mail Merge.
The MergeField Class
A merge field is an MS Word MERGEFIELD field, an ApplicationField in the document. The MergeField class in the TXTextControl.DocumentServer.Fields namespace is an adapter for it. The constructor without parameters creates a new field, and the constructor with an ApplicationField wraps an existing one. Its properties:
| Property | Sets |
|---|---|
| Name | The name that is matched with the data |
| Text | The text the field shows until it's merged |
| TextBefore, TextAfter | Text shown before and after the value |
| NumericFormat | A format for numbers, the MS Word switch \# |
| DateTimeFormat | A format for dates and times, the MS Word switch \@ |
| TextFormat | The case of the letters: Uppercase, Lowercase, FirstCapital, TitleCase or None |
| DataSourceCulture, MergeCulture | The cultures that parse the value from the data and format it in the document |
In the Document Editor, the JavaScript TXTextControl.MergeField object has matching properties for the text before and after, the numeric, date and time formats and the text format.
MailMerge doesn't use the properties Mapped and VerticalFormatting, or PreserveFormatting, which MergeField inherits from MailMergeFieldAdapter. The formatting of the field in the template, such as its font and color, is always kept.
Format Numbers and Dates
NumericFormat accepts the standard and custom numeric format strings of .NET. A custom format can have separate sections for positive and negative numbers and zero, separated by ;:
| Format | 5000 | -5000 |
|---|---|---|
$##,###.00 | $5,000.00 | -$5,000.00 |
C2 | $5,000.00 | ($5,000.00) |
#,##0.00;(#,##0.00) | 5,000.00 | (5,000.00) |
DateTimeFormat accepts the standard and custom date and time format strings of .NET, such as MMMM d, yyyy.
The currency symbol, the decimal separator and the names of months depend on the culture that formats the value. Keep numbers and dates as typed values in the data, put the formats into the template and set the cultures of the merge explicitly, so that the result doesn't depend on the regional settings of the server. The blog article Format Numeric String Values with MailMerge lists the format specifiers.
Set Formats on All Fields of a Template
Merge fields can be in the main text, in headers and footers and in text frames. ServerTextControl.TextParts contains all these parts, each with its own ApplicationFields collection. The following program sets formats on three fields of template.docx, wherever they are, and merges the template with fixed cultures:
using System.Globalization;
using TXTextControl;
using TXTextControl.DocumentServer;
using TXTextControl.DocumentServer.Fields;
string jsonData = File.ReadAllText("data.json");
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
LoadSettings loadSettings = new LoadSettings()
{
ApplicationFieldFormat = ApplicationFieldFormat.MSWord,
LoadSubTextParts = true
};
tx.Load("template.docx", StreamType.WordprocessingML, loadSettings);
// The main text, text frames, headers and footers
foreach (IFormattedText textPart in tx.TextParts)
{
foreach (ApplicationField applicationField in textPart.ApplicationFields)
{
if (applicationField.TypeName != "MERGEFIELD")
{
continue;
}
MergeField mergeField = new MergeField(applicationField);
switch (mergeField.Name)
{
case "Customer.CustomerName":
mergeField.TextFormat = TextFormatOptions.Uppercase;
break;
case "AmountDue":
mergeField.TextBefore = "Amount due: ";
mergeField.NumericFormat = "$#,##0.00";
break;
case "DueDate":
mergeField.DateTimeFormat = "MMMM d, yyyy";
break;
}
}
}
using (MailMerge mailMerge = new MailMerge
{
TextComponent = tx,
DataSourceCulture = CultureInfo.InvariantCulture,
MergeCulture = CultureInfo.GetCultureInfo("en-US")
})
{
mailMerge.MergeJsonData(jsonData);
}
tx.Save("output.pdf", StreamType.AdobePDF);
}
The code works as follows:
- Each text part implements IFormattedText, whose ApplicationFields contains the fields of that part. TypeName is
MERGEFIELDfor merge fields. new MergeField(applicationField)wraps the field, and changes to its properties apply to the field in the document.CultureInfo.InvariantCultureparses the numbers and dates of the JSON data, and the US English culture formats them in the document.
Insert Date Fields
A DATE field shows the current date in a format. During the merge, MailMerge fills it with the date of the merge. The DateField adapter creates such a field:
using TXTextControl;
using TXTextControl.DocumentServer;
using TXTextControl.DocumentServer.Fields;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Selection = new Selection { Text = "Printed on: " };
DateField dateField = new DateField()
{
Format = "MMMM d, yyyy",
Date = DateTime.Now
};
tx.ApplicationFields.Add(dateField.ApplicationField);
using (MailMerge mailMerge = new MailMerge
{
TextComponent = tx,
DateFieldUtcOffset = 60 // minutes
})
{
mailMerge.MergeJsonData(File.ReadAllText("data.json"));
}
tx.Save("date.pdf", StreamType.AdobePDF);
}
DateField.Format is a .NET date and time format string, and Culture sets the culture that formats the date. MailMerge.DateFieldUtcOffset sets the offset from UTC in minutes for all date fields. With null, the default, the local date and time of the server are used.
In the Document Editor, users insert a DATE field with Date in the Insert Special Field drop-down of the Reporting tab. Your JavaScript code opens the dialog box for a new DATE field with TXTextControl.showMergeFieldDialog(TXTextControl.FieldType.DateField), as Conditional Content shows for IF fields.
Show a Text for Fields Without Data
A field without data is removed, because RemoveEmptyFields is true by default. To show a text instead, keep such fields and change their text in the FieldMerged event, which occurs for every field, whether it received data or not:
using (MailMerge mailMerge = new MailMerge
{
TextComponent = tx,
RemoveEmptyFields = false
})
{
mailMerge.FieldMerged += (sender, e) =>
{
if (!e.Merged && e.MailMergeFieldAdapter.TypeName == "MERGEFIELD")
{
MergeField mergeField = new MergeField(e.MailMergeFieldAdapter.ApplicationField);
mergeField.Text = "n/a";
}
};
mailMerge.MergeJsonData(jsonData);
}
The arguments of FieldMerged tell you more about the field:
| Property | Contains |
|---|---|
| Merged | Whether the field received data |
| MailMergeFieldAdapter | The merged field, which can be changed |
| DataRow | The data record; e.DataRow["AmountDue"] returns the value of a column |
| MergedField | The merged field as a byte array in the TX Text Control format, which can be replaced |
| MergeBlockName, TableCell | The merge block and the table cell that contain the field, if any |
Merge Formatted Text
A merge field receives plain text. To merge formatted text, such as HTML notes from a web form, replace the merged content in FieldMerged: load the text into a second ServerTextControl, save it in the TX Text Control format and assign the bytes to MergedField. With an HTML value in the invoice data, such as "Notes": "<p>Thank you for your <strong>business</strong>.</p>", and a merge field named Notes in the template:
mailMerge.FieldMerged += (sender, e) =>
{
if (e.Merged && e.MailMergeFieldAdapter is MergeField mergeField && mergeField.Name == "Notes")
{
using (ServerTextControl htmlText = new ServerTextControl())
{
htmlText.Create();
// The merged value is HTML: load it and replace the field with the result
htmlText.Load(mergeField.Text, StringStreamType.HTMLFormat);
byte[] data;
htmlText.Save(out data, BinaryStreamType.InternalUnicodeFormat);
e.MergedField = data;
}
}
};
The blog article MailMerge: Merging Hyperlinks using the FieldMerged Event replaces fields with hyperlinks in the same way and keeps the font and color of the field.
Keep Merge Fields After the Merge
By default, a merged field is removed and only its text stays in the document. When the merged document must be editable and merged again, for example to preview a template with data, assign MergedField to itself: the fields are then kept in the result.
mailMerge.FieldMerged += (sender, e) => e.MergedField = e.MergedField;
Merge Form Fields
Templates can contain form fields that users fill out later, for example in the Document Viewer. MailMerge.FormFieldMergeType decides whether they receive data:
| Value | Form fields |
|---|---|
None (default) | Aren't merged |
Preselect | Keep their controls, and their content is preselected with the data where possible; fields without a matching column stay unchanged |
Replace | Are replaced with the data, so the result has no form fields; empty form fields are removed according to RemoveEmptyFields |
The blog article Merging Form Fields using the MailMerge Class merges a form template with a check box, drop-down lists, a date and a text field and saves it as PDF. With Preselect, the fields stay fillable in Adobe Acrobat and show the merged values; with Replace, only the values remain as text:

The following merge fills the form fields of form.tx, a template with form fields named like the data, and reports each field in the FormFieldMerged event:
using TXTextControl;
using TXTextControl.DocumentServer;
using (ServerTextControl tx = new ServerTextControl())
{
tx.Create();
tx.Load("form.tx", StreamType.InternalUnicodeFormat);
using (MailMerge mailMerge = new MailMerge
{
TextComponent = tx,
FormFieldMergeType = FormFieldMergeType.Preselect
})
{
mailMerge.FormFieldMerged += (sender, e) =>
Console.WriteLine($"{e.FormField.Name}: {(e.Merged ? "merged" : "no data")}");
mailMerge.MergeJsonData(File.ReadAllText("data.json"));
}
tx.Save("form-prefilled.tx", StreamType.InternalUnicodeFormat);
}
A template can contain merge fields and form fields together: data that users must not change goes into merge fields, and values that users may correct into preselected form fields. The blog article Merging Form Fields using the MailMerge Class shows such a template.
Prefixes in Field Names
A dot in a field name addresses related data: Customer.CustomerName is the column CustomerName of the related table or nested object Customer, and longer paths reach further levels. The prefix image: has a special meaning: it marks a merge field that is merged as an image, as Images describes.
Inside a merge block, a prefix starts at the table of the block, not at the master table. The sample database of TX Text Control Words shows this with three tables: the orders in Sales_SalesOrderHeader, their order lines in Sales_SalesOrderDetail, related by SalesOrderID, and the products in Production_Product, related to each order line by ProductID:

With Sales_SalesOrderHeader as the master table, an invoice template has these fields:
| Where | Field | Value |
|---|---|---|
| Outside all blocks | OrderDate | A column of the order |
In the merge block Sales_SalesOrderDetail | OrderQty, UnitPrice, LineTotal | Columns of the current order line, without a prefix |
| In the same block | Production_Product.ProductNumber, Production_Product.Name | Columns of the product of the current order line |

You pass only the master table to Merge, and MailMerge follows the relations to the order lines and their products. Nested Blocks shows a DataSet with such a relation in code, and image placeholders take prefixes in the same way, as Images shows.

Next Steps
- Conditional Content: insert text with
IFfields depending on the data. - Styling: format merged cells and rows in code.
- Merge Blocks: repeat fields for each record of a collection.
- Fields in Document Processing: the other kinds of fields.