Template Preview
Designers of a template want to know what it produces before anyone merges real data: does the table grow, do empty lines disappear, are the prices formatted? A preview answers this in the editor itself. It merges the template in the WPF TextControl with the sample data of the Reporting tab, shows a few merged records one after the other and returns to the template when the designer is done. A toggle button and two buttons in XAML, plus some code behind, are all it takes.
The preview uses the data loaded into the tab, as in Create a Template. Merging the real data is a separate step with MailMerge, shown in Merge Data into Fields.
How a Preview Works
The WPF Reporting tab has no preview button, but its DataSourceManager merges a template with the data it holds. Merge takes the template as a byte array in the internal TX Text Control format and returns a list with one merged document per record, limited to a number of records you choose. A preview therefore:
- saves the template from the editor into a byte array and keeps it,
- merges the byte array and loads a merged record into the editor,
- loads the kept template again when the designer returns to it.
The TX Words Reporting sample for WPF works this way. Its Merge and Export button asks for the number of records and the empty elements to remove in a Merge Settings dialog box of the sample:

A Results tab then pages through the merged records, and its Export Merge Result dialog box saves them as files:

The source code of the sample is in %USERPROFILE%\Documents\TX Text Control 34.0.NET for WPF\CSharp\TX Words\Reporting.
Add a Preview
The following code extends the window of Create a Template, which has a RibbonReportingTab named ribbonReportingTab1 and a TextControl named textControl1. Add a toggle button and two buttons to the DockPanel of MainWindow.xaml, before the TextControl element:
<StackPanel DockPanel.Dock="Top" Orientation="Horizontal">
<ToggleButton x:Name="previewToggle" Content="Preview"
Checked="previewToggle_Checked" Unchecked="previewToggle_Unchecked" />
<Button x:Name="previousRecordButton" Content="Previous" Click="previousRecordButton_Click" />
<Button x:Name="nextRecordButton" Content="Next" Click="nextRecordButton_Click" />
</StackPanel>
The handlers go into MainWindow.xaml.cs:
using System.Collections.Generic;
using System.Windows;
using TXTextControl;
using TXTextControl.DocumentServer.DataSources;
private byte[] template;
private IList<byte[]> previews;
private int previewIndex;
private void previewToggle_Checked(object sender, RoutedEventArgs e)
{
DataSourceManager dataSourceManager = ribbonReportingTab1.DataSourceManager;
if (!dataSourceManager.IsMergingPossible)
{
MessageBox.Show(this, "Load a data source into the Reporting tab first.");
previewToggle.IsChecked = false;
return;
}
// Keep the template to restore it later
textControl1.Save(out template, BinaryStreamType.InternalUnicodeFormat);
MergeSettings mergeSettings = new MergeSettings
{
RemoveEmptyFields = true,
RemoveEmptyLines = false,
RemoveEmptyImages = false
};
// Merge the first five records, one document each
previews = dataSourceManager.Merge(template, 5, textControl1, mergeSettings);
previewIndex = 0;
ShowRecord();
textControl1.EditMode = EditMode.ReadAndSelect;
}
private void previewToggle_Unchecked(object sender, RoutedEventArgs e)
{
if (template == null)
{
return;
}
// Bring back the template and make it editable again
textControl1.Load(template, BinaryStreamType.InternalUnicodeFormat);
textControl1.EditMode = EditMode.Edit;
template = null;
previews = null;
Title = "Template";
}
private void ShowRecord()
{
textControl1.Load(previews[previewIndex], BinaryStreamType.InternalUnicodeFormat);
Title = $"Preview: record {previewIndex + 1} of {previews.Count}";
}
private void nextRecordButton_Click(object sender, RoutedEventArgs e)
{
if (previews != null && previewIndex < previews.Count - 1)
{
previewIndex++;
ShowRecord();
}
}
private void previousRecordButton_Click(object sender, RoutedEventArgs e)
{
if (previews != null && previewIndex > 0)
{
previewIndex--;
ShowRecord();
}
}
The code works as follows:
- The
CheckedandUncheckedevents of theToggleButtonswitch between the preview and the template. - IsMergingPossible is
falsewhile the requirements ofMergearen't met, for example before data is loaded. The toggle button is then reset. textControl1.Savewrites the template with its fields and blocks intotemplate, inBinaryStreamType.InternalUnicodeFormat.Mergemerges at most five records into five documents. TheWPF.TextControlis passed for licensing.- MergeSettings control what the merge removes. RemoveEmptyLines and RemoveEmptyImages are
trueby default here andfalseby default inMailMerge; the code sets both tofalse, so the preview looks like a merge with the default settings ofMailMerge. - EditMode set to
ReadAndSelectkeeps users from editing the preview, whose changes would be lost. ShowRecordloads one merged document and shows its number in the title of the window.
Press F5, load data into the Reporting tab and click Preview. The first record appears; Next and Previous page through the others, and a second click on Preview restores the template.
Merge Settings
MergeSettings has these properties:
| Property | Default | What it does |
|---|---|---|
| AsSingleDocument | false | Combines the records into one document; each record starts on a new page after a section break |
| RemoveEmptyBlocks | true | Removes the content of merge blocks without data |
| RemoveEmptyFields | true | Removes fields without data |
| RemoveEmptyImages | true | Removes images without merge data |
| RemoveEmptyLines | true | Removes lines that are empty after the merge |
| RemoveTrailingWhitespace | true | Removes trailing whitespace |
With AsSingleDocument, the returned list holds a single document with all records, which designers scroll through instead of paging. MergeCulture of the DataSourceManager sets the culture that formats numbers and dates; by default, it is the culture of the current thread.
Find Fields Without Data in the Preview
During Merge, the DataSourceManager raises FieldMerged and DataRowMerged with the same arguments as the events of MailMerge. A FieldMerged handler can collect the fields whose Merged property is false and show them beside the preview; Template Design does the same with MailMerge.
Preview With MailMerge
DataSourceManager.Merge uses the data the designer loaded into the tab. When the preview must use the data and settings of your real merge, merge with MailMerge in a ServerTextControl and load the result into the editor, as Merge Data into Fields does. The description of the TX Words sample also recommends MailMerge for merging real documents, and uses the DataSourceManager for its preview only.
Next Steps
- Reporting Ribbon and WPF Dialog Boxes: the tab whose data the preview merges.
- Template Design: test templates before they are used.
- Merge Events: follow a merge with events.