TX Text Control .NET for Windows Forms

Add Repeating Merge Blocks

Topic

An invoice has one customer but many items, and the template cannot know how many. A merge block solves this: a part of the template, such as a table row, that is repeated once for each record of a list in the data. Following on from the invoice of the previous tutorials, you add a block for the Items of invoice.json, merge it, and see the same result with business objects.

Prerequisites

How Merge Blocks Work

A merge block is a named part of the document whose name starts with txmb_, followed by the name of a list in the data. Here the block is txmb_Items, and the list is the Items array of the JSON data. During the merge, the block is copied once for each item, with its formatting, and the merge fields inside it receive the values of that item: Description, Quantity and Price.

A block can be a table row, a complete table, paragraphs or other content. For an invoice, a table row is the natural choice: the table grows by one row per item. In the following template of the Windows Forms mail merge sample, the highlighted table row is a merge block:

A template in the Windows Forms mail merge sample with merge fields above a table whose highlighted second row is a merge block.

After the merge, the table has one row for each record of the block's data:

The merged document in the Windows Forms mail merge sample, in which the table has two rows created from the merge block.

Insert the Block With the Ribbon

  1. Press F5 and design the template as in Create a Template.

  2. Place the input position where the table of items goes.

  3. Open the Insert Merge Block drop-down in the Merge Blocks group of the Reporting tab and select Items. The drop-down lists the tables of the data source that can become a block:

    The Insert Merge Block drop-down of the Reporting tab, here listing the tables of another data source, with Insert Custom Merge Block and Highlight Merge Blocks below them.

  4. In the dialog box, select the columns Description, Quantity and Price and confirm with OK. Table Row and Add table header row create the block as a table row below a header row:

    The Insert Merge Block dialog box with checked columns, the buttons Move up, Move down and Filter & Sort, the options Table Row and Plain paragraph, Add table header row and Color.

  5. Save the template again as invoice.docx.

The Reporting tab inserts a table row with the three merge fields and marks it as the block.

Insert the Block in Code

The same block can be inserted by your code. Add the following using directives and methods to Form1:

using System.Collections.Generic;
using TXTextControl.DocumentServer.DataSources;
using TXTextControl.DocumentServer.Windows.Forms;
private void insertItemsBlockButton_Click(object sender, EventArgs e)
{
    // The Items block and the merge fields it contains
    MergeBlockInfo mergeBlockInfo = new MergeBlockInfo("Items")
    {
        ColumnNames = new List<string> { "Description", "Quantity", "Price" }
    };

    // A table row that is repeated for each item, below a header row
    MergeBlockSettings mergeBlockSettings = new MergeBlockSettings(BlockTemplateType.TableRow, true);

    // Insert the block at the current input position
    ribbonReportingTab1.DataSourceManager.InsertMergeBlock(textControl1, mergeBlockInfo, mergeBlockSettings);
}

private void insertItemsBlockDialogButton_Click(object sender, EventArgs e)
{
    DataSourceManager dataSourceManager = ribbonReportingTab1.DataSourceManager;

    // Let the user choose the columns of the Items block
    using (InsertMergeBlockDialog dialog = new InsertMergeBlockDialog(
        dataSourceManager, textControl1, dataSourceManager.DataTables["Items"]))
    {
        dialog.ShowDialog(this);
    }
}

The code works as follows:

Merge the Template

The merge code of Merge Data into Fields does not change. It loads the template with LoadSubTextParts set to true, which imports the block, and MergeJsonData fills the block from the Items array, like the fields from the other properties.

Click mergeButton. The invoice now has a table with one row for Consulting and one for Training. The content of a block without data is removed, because RemoveEmptyBlocks is true by default.

Merge Business Objects Instead

The same template works with business objects. A property whose type is a collection fills the block of the same name:

using System.Collections.Generic;

public class Invoice
{
    public string Company { get; set; }
    public string Name { get; set; }
    public string InvoiceNumber { get; set; }
    public List<InvoiceItem> Items { get; set; } = new List<InvoiceItem>();
}

public class InvoiceItem
{
    public string Description { get; set; }
    public int Quantity { get; set; }
    public decimal Price { get; set; }
}

In the merge code, replace the call of MergeJsonData with MergeObject:

Invoice invoice = new Invoice { Company = "Contoso Ltd.", Name = "Jane Miller", InvoiceNumber = "INV-1001" };
invoice.Items.Add(new InvoiceItem { Description = "Consulting", Quantity = 2, Price = 150.00m });
invoice.Items.Add(new InvoiceItem { Description = "Training", Quantity = 1, Price = 480.00m });

mailMerge.MergeObject(invoice);

Next Steps