TX Text Control .NET for WPF

Template Preview

Topic

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:

  1. saves the template from the editor into a byte array and keeps it,
  2. merges the byte array and loads a merged record into the editor,
  3. 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:

TX Text Control Words for WPF with an invoice template, the Reporting tab, the Merge Settings dialog box with the number of records, Merge all records, Merge into single document and check boxes for removing empty blocks, fields, lines, images and trailing whitespace, and the Field Navigation sidebar

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

TX Text Control Words for WPF with a merged invoice, the Results tab with the buttons Exit, First Record, Previous Record, Next Record, Last Record and Export Merge Result, and the Export Merge Result dialog box

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 Checked and Unchecked events of the ToggleButton switch between the preview and the template.
  • IsMergingPossible is false while the requirements of Merge aren't met, for example before data is loaded. The toggle button is then reset.
  • textControl1.Save writes the template with its fields and blocks into template, in BinaryStreamType.InternalUnicodeFormat.
  • Merge merges at most five records into five documents. The WPF.TextControl is passed for licensing.
  • MergeSettings control what the merge removes. RemoveEmptyLines and RemoveEmptyImages are true by default here and false by default in MailMerge; the code sets both to false, so the preview looks like a merge with the default settings of MailMerge.
  • EditMode set to ReadAndSelect keeps users from editing the preview, whose changes would be lost.
  • ShowRecord loads 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:

PropertyDefaultWhat it does
AsSingleDocumentfalseCombines the records into one document; each record starts on a new page after a section break
RemoveEmptyBlockstrueRemoves the content of merge blocks without data
RemoveEmptyFieldstrueRemoves fields without data
RemoveEmptyImagestrueRemoves images without merge data
RemoveEmptyLinestrueRemoves lines that are empty after the merge
RemoveTrailingWhitespacetrueRemoves 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