Merge Data Into Fields
Merging is the step that turns a template into a finished document: MailMerge looks up each merge field by its name in the data and writes the value in its place. The invoice template of Create a Template and invoice.json come together here in a button handler of your WPF window. It merges in the background, shows the invoice in the editor, saves a PDF and reports the fields that received no value.
Prerequisites
The ribbon window from Create a Template, with invoice.docx and invoice.json in the output folder.
A button for the merge in the
DockPanelof MainWindow.xaml, before theTextControlelement:<Button x:Name="mergeButton" DockPanel.Dock="Top" Content="Merge" Click="mergeButton_Click" />
Add these using directives to MainWindow.xaml.cs, next to those of Create a Template:
using System.Collections.Generic;
using TXTextControl.DocumentServer;
How a Merge Works
MailMerge works on the document of another component. Its TextComponent property takes a ServerTextControl or a WPF TextControl that holds the template. A merge method replaces the merge fields with values from the data, and the component then holds the merged document.
The handler below merges in a ServerTextControl. The template the user designs in the editor stays as it is, and only the result is loaded into the editor.
Merge the Data
private void mergeButton_Click(object sender, RoutedEventArgs e)
{
List<string> fieldsWithoutData = new List<string>();
byte[] result;
using (ServerTextControl tx = new ServerTextControl())
{
// Initialize the new instance before using it
tx.Create();
// Import the Word merge fields and merge blocks of the DOCX template
LoadSettings loadSettings = new LoadSettings
{
ApplicationFieldFormat = ApplicationFieldFormat.MSWord,
LoadSubTextParts = true
};
tx.Load("invoice.docx", StreamType.WordprocessingML, loadSettings);
using (MailMerge mailMerge = new MailMerge { TextComponent = tx })
{
// Collect the name of every merge field without a value
mailMerge.FieldMerged += (s, args) =>
{
if (!args.Merged && args.MailMergeFieldAdapter is MergeField mergeField)
{
fieldsWithoutData.Add(mergeField.Name);
}
};
// Replace the merge fields with the values of the JSON data
mailMerge.MergeJsonData(File.ReadAllText("invoice.json"));
}
// Save the invoice as PDF, and as a byte array for the editor
tx.Save("invoice.pdf", StreamType.AdobePDF);
tx.Save(out result, BinaryStreamType.InternalUnicodeFormat);
}
// Show the merged invoice in the editor
textControl1.Load(result, BinaryStreamType.InternalUnicodeFormat);
if (fieldsWithoutData.Count > 0)
{
MessageBox.Show(this, "No data for: " + string.Join(", ", fieldsWithoutData));
}
}
The code works as follows:
- Loading the template. In a DOCX file, merge fields are fields of Microsoft Word. With ApplicationFieldFormat set to
MSWord,Loadimports them as fields thatMailMergerecognizes, and LoadSubTextParts imports the merge blocks of the next tutorial. Loaded without these settings, the template has no fields to merge. - Connecting.
TextComponent = txmakes theServerTextControlwith the template the document thatMailMergeworks on. - Merging. MergeJsonData takes a JSON string with a single object or an array of objects of the same structure, and fills every field with the property of the same name. An array with several objects produces one invoice per object, appended to one document.
- Fields without data. FieldMerged occurs for each field. Merged is
falsewhen the data had no value for it, and MailMergeFieldAdapter is the field itself. - The result. After the merge, the
ServerTextControlholds the invoice. It is saved as invoice.pdf and passed to the editor as a byte array.
Run the Merge
Press F5 and click Merge. The editor shows the invoice with Contoso Ltd., Jane Miller and INV-1001 where the fields were, and invoice.pdf is in the output folder. If you add a field to the template for which invoice.json has no property, save the template and merge again, the message box names that field.
Control Empty Fields and Lines
Two properties of MailMerge decide what remains of a field without a value. RemoveEmptyFields, true by default, removes the field. RemoveEmptyLines, false by default, also removes the lines that are empty after the merge, such as a second address line. Set both before calling the merge method.
Merge Directly in the Editor
MailMerge can also work on the TextControl of the window. Then the document in the editor is the template, and after the merge the editor shows the result. The WPF mail merge sample of the installation works this way:
private void mergeInEditorButton_Click(object sender, RoutedEventArgs e)
{
// The editor holds the template and afterward the merged invoice
using (MailMerge mailMerge = new MailMerge { TextComponent = textControl1 })
{
mailMerge.MergeJsonData(File.ReadAllText("invoice.json"));
}
}

Load the template into the editor with the same LoadSettings before merging. This way suits a window whose only job is to produce the document. When users design templates in the editor, merge in a ServerTextControl as above, so that the template survives the merge.
Other Kinds of Data
MailMerge has one merge method for each kind of data: Merge for a DataTable, MergeObject for a business object and MergeObjects for a collection of business objects. The field names are the column names or the names of the public properties. MailMerge in the Overview compares the data sources.
Next Steps
- Add Repeating Merge Blocks: add a table row for each invoice item.
- Data Sources: JSON, business objects, DataSets and configuration files in detail.
- Merge Events: change fields and blocks while they are merged.
- Mail Merge in Troubleshooting: fields that stay empty, blocks that don't repeat and wrong formats.