# Merge Blocks

> Merge blocks in Windows Forms: the Insert Merge Block dialog, InsertMergeBlock with paragraph blocks, GetBlockNames and the block at the input position.

- **Product:** TX Text Control .NET for Windows Forms
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for Windows Forms > Mail Merge and Reporting > Merge Blocks
- **4732 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/blocks/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/blocks/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/blocks/llms-full.txt

---

A merge block is the part of a template that `MailMerge` repeats for each record of a list: the line items of an invoice, the positions of a delivery note or the clauses of a contract. A block can also stand for one object and vanish when the data doesn't contain it. What follows goes beyond the first block of Getting Started: what a block may contain, how it is stored, the block tools of the Reporting tab, blocks created and inspected by your code, and what happens to blocks without data.

[Add Repeating Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/getting-started/mail-merge/blocks/llms-full.txt) in Getting Started inserts the `Items` block of the invoice template *invoice.docx* and merges it with *invoice.json*. The examples below use the same form, with `textControl1` and the Reporting tab `ribbonReportingTab1`, which has *invoice.json* loaded. Blocks inside blocks are the subject of [Nested Blocks and Master-Detail Reports](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/nested-blocks/llms-full.txt).

### What a Merge Block Contains

A block isn't limited to a table row. It can hold a complete table, paragraphs, images, text frames or a single word, and `MailMerge` copies the whole block, formatting included, once for each record:

- **Breaks are copied too.** A paragraph end in the block starts a new paragraph per record; a page break, section break or column break in the block is inserted per record.
- **Each record on a new page.** When the first paragraph of the block has `PageBreakBefore` set in its paragraph format, every copy of the block starts on a new page, as the blog article [MailMerge: Starting Each Merge Block on a New Page](https://www.textcontrol.com/blog/2016/09/09/mailmerge-starting-each-merge-block-on-a-new-page/) shows.
- **Table header rows.** A header row above a table row block is repeated at the top of each page. To give each copy of a block a header of its own, make the complete table the block, as [Repeat Table Headers per Block](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/nested-blocks/#repeat-table-headers-per-block) explains.
- **Fields, images and barcodes** in the block receive the values of the current record.

### How Blocks Are Stored

In the document, a merge block is a [SubTextPart](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/llms-full.txt), a named range of text, whose name is `txmb_` followed by the block name. [MailMerge.MergeBlockNamePrefix](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/mergeblocknameprefix-property/llms-full.txt) returns this prefix. [Subtext Parts](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/document-editor/subtext-parts/llms-full.txt) describes the element itself.

- **DOCX, DOC and RTF.** Load templates in these formats with [LoadSettings.LoadSubTextParts](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/loadsettings/loadsubtextparts-property/llms-full.txt) set to `true`, as [Merge Data into Fields](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/getting-started/mail-merge/fields/llms-full.txt) does. Otherwise the blocks aren't imported.
- **Older templates** mark a block with two document targets named `blockstart_` and `blockend_` followed by the block name. This format is still supported.
- **Saving.** [ReportingMergeBlockFormat](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/loadsavesettingsbase/reportingmergeblockformat-property/llms-full.txt) of `SaveSettings` decides how blocks are written: `Default` keeps them as they are, and `DocumentTargets` converts subtext part blocks into the older document targets, for applications that still expect them.

Sorting and filter instructions are stored with the block, as [Sorting and Filtering](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/sorting-filtering/#where-the-instructions-are-stored) explains.

### Work With Blocks in the Reporting Tab

The **Merge Blocks** group of the Reporting tab holds everything a template designer needs for blocks. The **Insert Merge Block** drop-down lists the tables of the loaded data source:

![The Insert Merge Block drop-down of the Windows Forms Reporting tab with three tables of the sample database, Insert Custom Merge Block and Highlight Merge Blocks.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/insert-merge-block-menu.fa8d7908.webp)

- **A table** of the list opens the **Insert Merge Block** dialog box for that table.
- **Insert Custom Merge Block** makes the selected text a block with a name you type, for data the loaded data source doesn't contain.
- **Highlight Merge Blocks** marks all blocks of the template.
- **Edit Merge Block**, the second button of the group, renames or removes the blocks of the document.

In the dialog box, you check the columns that become merge fields of the block, including columns of related tables, and order them with **Move up** and **Move down**. **Table Row** creates the block as a table row, **Plain paragraph** as paragraphs, and **Add table header row** adds a row with the column names above a table row block. **Color** sets the color that highlights the block while the input position is in it, and **Filter & Sort** adds the instructions described in [Sorting and Filtering](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/sorting-filtering/llms-full.txt):

![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.](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-winforms/insert-merge-block-dialog.9f32db99.webp)

Your code opens the same dialog boxes with [InsertMergeBlockDialog](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-windows-forms/insertmergeblockdialog/llms-full.txt), as Getting Started shows, and [EditMergeBlocksDialog](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-windows-forms/editmergeblocksdialog/llms-full.txt). [Reporting Ribbon and Dialog Boxes](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/ribbon-dialogs/llms-full.txt) describes the tab as a whole.

### Insert a Paragraph Block in Code

[DataSourceManager.InsertMergeBlock](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/datasourcemanager/insertmergeblock-method/llms-full.txt) inserts a block at the input position. Its [MergeBlockSettings](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblocksettings/llms-full.txt) decide what the block looks like:

| Property | Sets |
|---|---|
| [BlockTemplateType](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblocksettings/blocktemplatetype-property/llms-full.txt) | `TableRow` for a table row, `PlainParagraph` for paragraphs |
| [CreateHeaderRow](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblocksettings/createheaderrow-property/llms-full.txt) | Whether a table row block gets a header row |
| [HighlightColor](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblocksettings/highlightcolor-property/llms-full.txt) | The color of the block while the input position is in it; its alpha value is used |
| [FieldDisplayMode](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblocksettings/fielddisplaymode-property/llms-full.txt) | Whether the fields show their text or their field codes |

The following handler of a button named `insertItemListButton` inserts the invoice items as a list of paragraphs instead of a table. Add `using System.Drawing;`, `using TXTextControl.DocumentServer.DataSources;` and `using System.Collections.Generic;` to *Form1.cs*:

```csharp
private void insertItemListButton_Click(object sender, EventArgs e)
{
    // A paragraph for each item with two of its fields
    MergeBlockInfo itemsBlock = new MergeBlockInfo("Items")
    {
        ColumnNames = new List<string> { "Description", "Quantity" }
    };

    MergeBlockSettings settings = new MergeBlockSettings(BlockTemplateType.PlainParagraph)
    {
        // Shown while the input position is in the block
        HighlightColor = Color.FromArgb(64, Color.SteelBlue)
    };

    ribbonReportingTab1.DataSourceManager.InsertMergeBlock(textControl1, itemsBlock, settings);

    if (settings.AddResult != SubTextPartCollection.AddResult.Successful)
    {
        MessageBox.Show(this, "The merge block was not inserted: " + settings.AddResult);
    }
}
```

The code works as follows:

- [MergeBlockInfo](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblockinfo/llms-full.txt) names the block after the `Items` array, and its [ColumnNames](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblockinfo/columnnames-property/llms-full.txt) become merge fields.
- After the call, [AddResult](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblocksettings/addresult-property/llms-full.txt) holds a value of [SubTextPartCollection.AddResult](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpartcollection/addresult-enumeration/llms-full.txt), such as `Successful`, or a reason like `Overlapping` when the block would overlap another one.
- For a table row block, [CreatedTable](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblocksettings/createdtable-property/llms-full.txt) returns the new table, for example to format it.

### Find the Blocks of a Template

A template that users designed may contain other blocks than your data provides. Connected to `textControl1`, `MailMerge` lists the blocks of the document in the editor without merging it:

```csharp
private void listBlocksButton_Click(object sender, EventArgs e)
{
    StringBuilder report = new StringBuilder();

    using (MailMerge mailMerge = new MailMerge { TextComponent = textControl1 })
    {
        foreach (string blockName in mailMerge.GetBlockNames())
        {
            string[] fieldNames = mailMerge.GetBlockFieldNames(blockName);
            report.AppendLine(blockName + ": " + string.Join(", ", fieldNames));
        }
    }

    MessageBox.Show(this, report.ToString(), "Merge blocks");
}
```

[GetBlockNames](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/getblocknames-method/llms-full.txt) returns the names of all blocks, and [GetBlockFieldNames](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/getblockfieldnames-method/llms-full.txt) the merge fields of one block. The handler needs `using System.Text;` and `using TXTextControl.DocumentServer;`. For the invoice template, the message shows `Items: Description, Quantity, Price`.

Your application can also react to the block the user is working in, for example to enable a button. [SubTextParts.GetItem](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpartcollection/getitem-method/llms-full.txt) without parameters returns the subtext part at the input position:

```csharp
private void currentBlockButton_Click(object sender, EventArgs e)
{
    // The innermost subtext part at the input position, or null
    SubTextPart subTextPart = textControl1.SubTextParts.GetItem();

    if (subTextPart == null || !DataSourceManager.IsMergeBlock(subTextPart))
    {
        MessageBox.Show(this, "The input position is not in a merge block.");
        return;
    }

    MergeBlockInfo mergeBlockInfo = new MergeBlockInfo(subTextPart);

    MessageBox.Show(this,
        $"Block {mergeBlockInfo.TableName}, level {subTextPart.NestedLevel}, " +
        $"{mergeBlockInfo.MergeFields.Length} merge fields");
}
```

- [DataSourceManager.IsMergeBlock](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/datasourcemanager/ismergeblock-method/llms-full.txt) tells a merge block from other subtext parts.
- A `MergeBlockInfo` created from a subtext part describes an existing block. [TableName](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblockinfo/tablename-property/llms-full.txt) is the name of its data, and [MergeFields](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-datasources/mergeblockinfo/mergefields-property/llms-full.txt) holds its fields without those of nested blocks.
- [NestedLevel](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/nestedlevel-property/llms-full.txt) is 1 for a block at the top level.

### Rename Blocks and Fields in Code

Block names and prefixed field names must follow the data. When a table or an array of the data gets a new name, every template that uses it needs the new name too. **Edit Merge Block** renames the blocks of one template; for many templates, your code renames them. A block is a subtext part named `txmb_` and the block name, and a field of a related table carries the table name before the dot, so both are renamed with string operations. The following method of *Form1.cs* renames a table in the template in `textControl1`:

```csharp
using TXTextControl;
using TXTextControl.DocumentServer;
using TXTextControl.DocumentServer.Fields;
```

```csharp
private void RenameDataTable(string oldName, string newName)
{
    string oldBlockName = MailMerge.MergeBlockNamePrefix + oldName;

    // The main text, text frames, headers and footers
    foreach (IFormattedText textPart in textControl1.TextParts)
    {
        // Merge blocks are subtext parts named txmb_ and the block name
        foreach (SubTextPart subTextPart in textPart.SubTextParts)
        {
            if (subTextPart.Name == oldBlockName)
            {
                subTextPart.Name = MailMerge.MergeBlockNamePrefix + newName;
            }
        }

        // Merge fields that address the table with dot notation, such as Items.Price
        foreach (ApplicationField applicationField in textPart.ApplicationFields)
        {
            if (applicationField.TypeName != "MERGEFIELD")
            {
                continue;
            }

            MergeField mergeField = new MergeField(applicationField);

            if (mergeField.Name.StartsWith(oldName + "."))
            {
                mergeField.Name = newName + mergeField.Name.Substring(oldName.Length);
            }
        }
    }
}
```

The code works as follows:

- [TextParts](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/textcontrol/textparts-property/llms-full.txt) holds the main text, the text frames and the headers and footers. Each part has its own [SubTextParts](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/iformattedtext/subtextparts-property/llms-full.txt) and `ApplicationFields`.
- A subtext part whose [Name](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol/subtextpart/name-property/llms-full.txt) is `txmb_Items` is the block `Items`. Setting `Name` renames the block.
- A `MergeField` wrapped around each merge field changes [Name](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver-fields/mergefield/name-property/llms-full.txt) in the document. Fields inside the block need no change, because their names don't contain the table name.

`RenameDataTable("Items", "LineItems")` adapts the invoice template to data whose array is named `LineItems`. Save the template afterward. The blog article [Renaming Merge Blocks and Merge Fields Programmatically in C#](https://www.textcontrol.com/blog/2024/02/08/renaming-merge-blocks-and-merge-fields-programmatically-in-csharp/) wraps the same steps in a helper class.

### Use a Block for a Single Object

A block doesn't have to repeat: named like a single nested object of the data, it is merged once if the object exists and removed when it doesn't. [Include Optional Sections](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/conditional-content/#include-optional-sections) builds optional sections of a document this way.

### Follow Blocks During the Merge

Two events accompany each block: [BlockMerging](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/blockmerging-event/llms-full.txt) occurs before a block is merged and hands over its data, and [BlockRowMerged](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/blockrowmerged-event/llms-full.txt) occurs after each merged row, which your code can change. [Merge Events](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/events/llms-full.txt) describes both, and [Formatting and Styling](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/styling/llms-full.txt) uses them to format merged rows.

### Merge Blocks From a DataSet

With a `DataSet`, each block is named like the `DataTable` that fills it, and a `DataRelation` connects the table to the master table. [MailMerge.Merge](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/merge-method/llms-full.txt) with the master table fills the fields outside the blocks from the master table and each block from the related table of the same name; [DataSets and DataTables](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/data-sources/datasets/llms-full.txt) shows the details.

[MergeBlocks](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/reference/txtextcontrol-documentserver/mailmerge/mergeblocks-method/llms-full.txt) is an older method that merges only the blocks. Since version 20.0, `Merge` processes the relations itself; [Deprecated APIs](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/whats-new/deprecated-apis/llms-full.txt) lists `MergeBlocks` with its replacement.

### Render a Block as a Numbered List

To merge records as the items of a numbered list, put the merge fields into a numbered list item and add an empty list item below it. Select from the start of the fields to the empty item, so that the paragraph end of the first item is part of the selection, and make the selection a block. Each record then becomes an item of the list with its own number. The blog article [Reporting: Merge Blocks Rendered As Numbered Lists](https://www.textcontrol.com/blog/2016/05/05/reporting-merge-blocks-rendered-as-numbered-lists/) shows such a template.

### Next Steps

- [Nested Blocks and Master-Detail Reports](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/nested-blocks/llms-full.txt): blocks inside blocks for orders and their items.
- [Sorting and Filtering](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/sorting-filtering/llms-full.txt): merge the rows of a block in order and only the rows you need.
- [Conditional Content](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/conditional-content/llms-full.txt): include or leave out sections depending on the data.
- [Template Preview](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/template-preview/llms-full.txt): show users the merged blocks while they design.

---

## Nearby

- **Previous:** [Merge Fields](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/fields/llms-full.txt)
- **Next:** [Nested Blocks and Master-Detail Reports](https://docs.textcontrol.com/tx-text-control-dotnet-winforms/mail-merge/nested-blocks/llms-full.txt)
