# Formatting and Styling

> Style merged WPF documents: template formatting that survives the merge, alternate row colors, TableCell and MergedField changes in FieldMerged handlers.

- **Product:** TX Text Control .NET for WPF
- **Section:** Documentation
- **Kind:** Topic
- **Path:** TX Text Control .NET for WPF > Mail Merge and Reporting > Formatting and Styling
- **4031 words**
- **Web URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/styling/
- **LLMs URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/styling/llms.txt
- **LLMs-Full URL:** https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/styling/llms-full.txt

---

Where does the look of a merged document come from? Mostly from the template: fonts, colors, table borders and paragraph settings are designed in the `TextControl` of your WPF window and survive the merge unchanged. Formatting that depends on the data, such as shaded alternate rows or a highlighted value, is added either by fields in the template or by handlers of the `MailMerge` events in *MainWindow.xaml.cs*.

Number and date formats of single merge fields belong to [Merge Fields](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/fields/llms-full.txt). The examples here continue the invoice of the Getting Started tutorials, the template *invoice.docx* with the table row block `Items` from [Add Repeating Merge Blocks](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/getting-started/mail-merge/blocks/llms-full.txt) and the data *invoice.json* with two items: *Consulting* (quantity 2, price 150.00) and *Training* (quantity 1, price 480.00).

### What the Merge Keeps

The merge fills the template with values and leaves its design alone:

- **Merge fields keep their formatting.** A value takes the font, size, style and color that its field has in the template.
- **Merge blocks are copied with their formatting.** Every record gets a copy of the block with its table formatting, paragraph settings and styles.
- **Letter case** is an option of the field: the **Format** list of the **Merge Field Options** dialog box offers UPPERCASE, lowercase, First capital and Title Case.

In the mail merge sample of the WPF installation, the template's table row block has bold names and italic quantities:

![A WPF window with a mail merge template whose table row holds merge fields, the Name field bold and the Qty field italic, and the Mail Merge menu open](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-wpf/merge-block-sample-template.321446fd.webp)

After the merge, each record has a row of its own, and every row keeps the bold and italic formatting of the template:

![The merged document in the WPF sample with two table rows for TX Text Control products, names in bold and quantities in italic](https://docs.textcontrol.com/assets/img/tx-text-control-dotnet-wpf/merge-block-merged-rows.7bf0c5ba.webp)

Keep formatting out of the data and in the template. [Template Design](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/template-design/llms-full.txt) lists the layout rules for templates that grow with their data.

### Alternate Row Colors in the Template

A template can alternate row colors on its own. Build the merge block from two table rows with the same merge fields and different background colors, and put a `NEXT` field at the end of the first row. The `NEXT` field advances to the next record, so the second row shows the following record in the second color. In the **Reporting** tab, the field is inserted with **Insert Special Field** in the **Merge Fields** group.

With an odd number of records, the second row of the last copy is left empty. The blog article [Reporting: Removing Empty Table Rows](https://www.textcontrol.com/blog/2014/09/30/reporting-removing-empty-table-rows/) removes that row in the `BlockRowMerged` event.

### Alternate Row Colors in Code

For a block of one row, your code colors every second row. The [BlockRowMerged](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge/blockrowmerged-event/llms-full.txt) event occurs after each row of a block and passes the merged row as a document. Add a button to *MainWindow.xaml*, next to the **Merge** button of the Getting Started tutorials:

```xml
<Button x:Name="colorRowsButton" DockPanel.Dock="Top" Content="Merge With Row Colors" Click="colorRowsButton_Click" />
```

The handlers go into *MainWindow.xaml.cs*. `MailMerge` events are ordinary .NET events, so your code attaches them with `+=`:

```csharp
using System;
using System.IO;
using System.Windows;
using TXTextControl;
using TXTextControl.DocumentServer;
using TXTextControl.DocumentServer.Fields;
```

```csharp
private int itemRowCount;

private void colorRowsButton_Click(object sender, RoutedEventArgs e)
{
    byte[] result;

    using (ServerTextControl tx = new ServerTextControl())
    {
        tx.Create();

        LoadSettings loadSettings = new LoadSettings
        {
            ApplicationFieldFormat = ApplicationFieldFormat.MSWord,
            LoadSubTextParts = true
        };

        tx.Load("invoice.docx", StreamType.WordprocessingML, loadSettings);

        using (MailMerge mailMerge = new MailMerge { TextComponent = tx })
        {
            mailMerge.BlockMerging += MailMerge_BlockMerging;
            mailMerge.BlockRowMerged += MailMerge_BlockRowMerged;

            mailMerge.MergeJsonData(File.ReadAllText("invoice.json"));
        }

        tx.Save(out result, BinaryStreamType.InternalUnicodeFormat);
    }

    // Show the merged invoice in the editor
    textControl1.Load(result, BinaryStreamType.InternalUnicodeFormat);
}

private void MailMerge_BlockMerging(object sender, MailMerge.BlockMergingEventArgs e)
{
    // Start counting again for each Items block
    if (e.BlockName == "Items")
    {
        itemRowCount = 0;
    }
}

private void MailMerge_BlockRowMerged(object sender, MailMerge.BlockRowMergedEventArgs e)
{
    if (e.MergeBlockName != "Items")
    {
        return;
    }

    // Color every second row of the block
    itemRowCount++;

    if (itemRowCount % 2 != 0)
    {
        return;
    }

    using (ServerTextControl rowText = new ServerTextControl())
    {
        rowText.Create();
        rowText.Load(e.MergedBlockRow, BinaryStreamType.InternalUnicodeFormat);

        foreach (TXTextControl.Table table in rowText.Tables)
        {
            foreach (TXTextControl.TableRow row in table.Rows)
            {
                TableCellFormat cellFormat = row.CellFormat;
                cellFormat.BackColor = System.Drawing.Color.LightGray;
                row.CellFormat = cellFormat;
            }
        }

        byte[] data;
        rowText.Save(out data, BinaryStreamType.InternalUnicodeFormat);
        e.MergedBlockRow = data;
    }
}
```

The code works as follows:

- The merge runs in a `ServerTextControl`, and the result is loaded into `textControl1`, the editor of the window.
- [BlockMerging](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge/blockmerging-event/llms-full.txt) occurs before a block is merged, and its [BlockName](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge-blockmergingeventargs/blockname-property/llms-full.txt) resets the counter for each `Items` block, so that every invoice of a larger array starts with a white row.
- [MergeBlockName](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge-blockrowmergedeventargs/mergeblockname-property/llms-full.txt) limits the change to the `Items` block.
- [MergedBlockRow](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge-blockrowmergedeventargs/mergedblockrow-property/llms-full.txt) contains the row in the internal TX Text Control format. A second `ServerTextControl` loads it, [TableRow.CellFormat](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablerow/cellformat-property/llms-full.txt) changes the background of its cells, and the saved bytes replace the row.
- The colors of `TableCellFormat` are `System.Drawing.Color` values, not WPF colors, so the code names the namespace in full.

Click **Merge With Row Colors**: the second row, *Training*, is gray.

### Highlight Cells Depending on Their Values

[FieldMerged](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge/fieldmerged-event/llms-full.txt) occurs for every merged field and passes the table cell the field is in. A handler can color that cell depending on the data of the record. Attach it with `mailMerge.FieldMerged += MailMerge_FieldMerged;`:

```csharp
private void MailMerge_FieldMerged(object sender, MailMerge.FieldMergedEventArgs e)
{
    // Highlight quantities above 1
    if (e.TableCell != null &&
        e.MailMergeFieldAdapter is MergeField mergeField &&
        mergeField.Name == "Quantity" &&
        Convert.ToInt32(e.DataRow["Quantity"]) > 1)
    {
        TableCellFormat cellFormat = e.TableCell.CellFormat;
        cellFormat.BackColor = System.Drawing.Color.LightYellow;
        e.TableCell.CellFormat = cellFormat;
    }
}
```

- [TableCell](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge-fieldmergedeventargs/tablecell-property/llms-full.txt) is the cell of the field, or `null` outside tables.
- [MailMergeFieldAdapter](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge-fieldmergedeventargs/mailmergefieldadapter-property/llms-full.txt) is the merged field. A merge field is a [MergeField](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver-fields/mergefield/llms-full.txt), whose name the rule checks.
- [DataRow](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge-fieldmergedeventargs/datarow-property/llms-full.txt) gives the values of the current record by column name.

The quantity cell of *Consulting* turns yellow. The blog article [Manipulating Table Cells During the MailMerge Process in .NET C#](https://www.textcontrol.com/blog/2024/12/03/manipulating-table-cells-during-the-mailmerge-process-in-net-csharp/) shows further rules of this kind.

### Color the Text of a Merged Field

To change the merged text itself, replace the content of the field. [MergedField](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge-fieldmergedeventargs/mergedfield-property/llms-full.txt) contains the merged field with its formatting, and the handler assigns a changed version back. This handler turns prices above 400 red; attach it with `mailMerge.FieldMerged += ColorPrice_FieldMerged;`:

```csharp
private void ColorPrice_FieldMerged(object sender, MailMerge.FieldMergedEventArgs e)
{
    if (e.Merged &&
        e.MailMergeFieldAdapter is MergeField mergeField &&
        mergeField.Name == "Price" &&
        Convert.ToDecimal(e.DataRow["Price"], System.Globalization.CultureInfo.InvariantCulture) > 400)
    {
        using (ServerTextControl fieldText = new ServerTextControl())
        {
            fieldText.Create();
            fieldText.Load(e.MergedField, BinaryStreamType.InternalUnicodeFormat);

            // Keep the text, remove the field, and color the text
            fieldText.ApplicationFields.Clear(true);
            fieldText.SelectAll();
            fieldText.Selection.ForeColor = System.Drawing.Color.Red;

            byte[] data;
            fieldText.Save(out data, BinaryStreamType.InternalUnicodeFormat);
            e.MergedField = data;
        }
    }
}
```

[Merged](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol-documentserver/mailmerge-fieldmergedeventargs/merged-property/llms-full.txt) is `true` when the field received a value. [ApplicationFields.Clear](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/applicationfieldcollection/clear-method/llms-full.txt) with `true` removes the field and keeps its text, which is then colored. Font and size stay as designed, because the field is loaded with its formatting.

### Number Formats and Formulas in Merged Tables

A table cell can have a number format of its own. With a number as the cell's text type, [TableCellFormat.NumberFormat](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/reference/txtextcontrol/tablecellformat/numberformat-property/llms-full.txt) formats the numbers in the cell, and that includes the value of a merge field placed in it, according to the blog article [Formatting Numbers in Table Cells](https://www.textcontrol.com/blog/2022/06/21/formatting-numbers-in-table-cells/).

Formula cells complete an invoice: the items come from the data, and formulas calculate the line totals and the total from the merged numbers. See [Tables and Calculations](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/tables/llms-full.txt) in Document Processing for formulas and number formats.

### Next Steps

- [Merge Fields](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/fields/llms-full.txt): formats, text before and after the value and formatted text.
- [Template Design](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/template-design/llms-full.txt): templates that work with small and large data.
- [Merge Events](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/events/llms-full.txt): all events of `MailMerge` and their arguments.
- [Tables and Calculations](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/document-processing/tables/llms-full.txt): format tables and cells in code.

---

## Nearby

- **Previous:** [Sorting and Filtering](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/sorting-filtering/llms-full.txt)
- **Next:** [Template Design](https://docs.textcontrol.com/tx-text-control-dotnet-wpf/mail-merge/template-design/llms-full.txt)
