# Add Repeating Merge Blocks

> Repeat a table row per invoice item in a WPF template: insert a merge block with the Reporting tab, InsertMergeBlock or InsertMergeBlockDialog, merge objects.

- **Product:** TX Text Control .NET for WPF
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for WPF > Getting Started > Mail Merge > Add Repeating Merge Blocks
- **2485 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/mail-merge/blocks/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/mail-merge/blocks/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/mail-merge/blocks/llms-full.txt

---

How many line items will an invoice have? The template can't know, so it contains the row for one item and lets the merge repeat it. Such a repeated part is a merge block. Continuing the invoice of the previous two tutorials, you add a block for the `Items` of *invoice.json* in the WPF window, with the Reporting tab or in code, merge it, and then fill the same template from business objects instead of JSON.

### Prerequisites

- The ribbon window from [Create a Template](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/mail-merge/template/llms-full.txt), which loads *invoice.json* into the Reporting tab when it opens.
- The **Merge** button and its handler from [Merge Data into Fields](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/mail-merge/fields/llms-full.txt).

### How Merge Blocks Work

A merge block is a named range of the template, a subtext part, whose name is `txmb_` followed by the name of a list in the data. The invoice needs the block `txmb_Items` for the `Items` array of the JSON data. During the merge, the range is copied once for each item, together with its formatting, and the merge fields inside it take the values of that item: `Description`, `Quantity` and `Price`.

Any content can form a block, from a table row to several paragraphs or a whole table. For line items, a table row is the usual choice, because the table grows by one row per item. In the following template of the WPF mail merge sample, the highlighted table row is a merge block:

![A template in the WPF mail merge sample with merge fields above a table whose highlighted second row is a merge block.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-wpf/merge-block-sample-template.321446fd.webp)

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

![The merged document in the WPF mail merge sample, in which the table has two rows created from the merge block.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-wpf/merge-block-merged-rows.7bf0c5ba.webp)

### Insert the Block With the Ribbon

1. Press **F5** and open or design the template as in [Create a Template](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/mail-merge/template/llms-full.txt).
2. Place the input position where the table of items belongs.
3. Open the **Insert Merge Block** drop-down in the **Merge Blocks** group of the **Reporting** tab and select **Items**.

    ![The Insert Merge Block drop-down of the WPF Reporting tab, listing the tables of a data source.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-wpf/insert-merge-block-menu.443672cc.webp)
4. In the dialog box, select the columns **Description**, **Quantity** and **Price** and click **OK**.
5. Save the template again as *invoice.docx*.

The tab inserts a table row with a merge field for each selected column and marks it as the block. **Highlight Merge Blocks** at the bottom of the same drop-down marks the blocks of the template, and the field navigator of [Create a Template](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/mail-merge/template/#show-the-field-navigation-sidebar) lists them on its **Merge Blocks** tab.

### Insert the Block in Code

Your code can insert the same block, with or without asking the user. Add these `using` directives to *MainWindow.xaml.cs*:

```csharp
using System.Collections.Generic;
using TXTextControl.DocumentServer.DataSources;
using TXTextControl.DocumentServer.WPF;
```

Then add two buttons, `insertItemsBlockButton` and `insertItemsBlockDialogButton`, to the `DockPanel` of *MainWindow.xaml* and these handlers to `MainWindow`:

```csharp
private void insertItemsBlockButton_Click(object sender, RoutedEventArgs 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, RoutedEventArgs e)
{
    DataSourceManager dataSourceManager = ribbonReportingTab1.DataSourceManager;

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

    dialog.ShowDialog();
}
```

The code works as follows:

- [MergeBlockInfo](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver-datasources/mergeblockinfo/llms-full.txt) names the list in the data, and its [ColumnNames](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver-datasources/mergeblockinfo/columnnames-property/llms-full.txt) become the merge fields of the block.
- [MergeBlockSettings](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver-datasources/mergeblocksettings/llms-full.txt) with `BlockTemplateType.TableRow` creates the block as a table row, and `true` adds a separate header row above it.
- [InsertMergeBlock](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver-datasources/datasourcemanager/insertmergeblock-method/llms-full.txt) inserts the block at the input position of the WPF `TextControl` that you pass.
- [InsertMergeBlockDialog](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver-wpf/insertmergeblockdialog/llms-full.txt) of the namespace `TXTextControl.DocumentServer.WPF` is the dialog box of the Reporting tab. It is a WPF `Window`: set its `Owner` and open it with `ShowDialog`. [DataTables](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver-datasources/datasourcemanager/datatables-property/llms-full.txt) returns the table of the loaded data by its name.

### Merge the Template

The merge code of [Merge Data into Fields](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/mail-merge/fields/llms-full.txt) needs no change. `LoadSubTextParts` set to `true` imports the block with the template, and `MergeJsonData` fills it from the `Items` array the way it fills the fields from the other properties.

Click **Merge**. The invoice now contains a table with one row for *Consulting* and one for *Training*. A block without data is removed with its content, because [RemoveEmptyBlocks](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge/removeemptyblocks-property/llms-full.txt) is `true` by default.

### Merge Business Objects Instead

The same template also works with business objects. A property that holds a collection fills the block of the same name. Add these classes to the project:

```csharp
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 `mergeButton_Click`, replace the call of `MergeJsonData` with a call of [MergeObject](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge/mergeobject-method/llms-full.txt):

```csharp
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);
```

The merged invoice is the same as with the JSON data.

### Next Steps

- [Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/blocks/llms-full.txt): block types, empty blocks and block events in detail.
- [Nested Blocks and Master-Detail Reports](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/nested-blocks/llms-full.txt): blocks inside blocks.
- [Sorting and Filtering](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/sorting-filtering/llms-full.txt): sort and filter the rows of a block.
- The blog article [Mail Merge: Inserting Merge Blocks using the DataSourceManager in C#](https://www.textcontrol.com/blog/2024/10/02/mail-merge-inserting-merge-blocks-using-the-datasourcemanager-in-csharp/): more ways to insert blocks in code.

---

## Nearby

- **Previous:** [Merge Data Into Fields](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/mail-merge/fields/llms-full.txt)
- **Next:** [PDF Processing](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/pdf/llms-full.txt)
