Manipulating Table Cells During the MailMerge Process in .NET C#
This article shows how to manipulate table cells during the mail merge process in .NET C#. The FieldMerged event can be used to manipulate the table cells after they are merged.

The Mail
At its core, the MailMerge class simplifies the complex task of creating professional, data-driven documents by allowing developers to easily merge fields in templates with data sources. Templates are designed using the TX Text Control word processing interface, with merge fields representing dynamic content.
Merge Blocks
Merge blocks are a key concept in TX Text Control's MailMerge class, which allows for the dynamic generation of structured, repeatable content in documents. Merge blocks allow developers to effectively handle repeating data structures such as lists, tables, or nested regions in templates.
At a high level, a merge block is a defined section within a template that corresponds to a collection or table of data. During the merge process, MailMerge iterates through the data source, dynamically creating content for each record. These merge blocks can be conditionally rendered, filtered, and sorted using the out-of-the-box functionality of the MailMerge class.
Code-Level Manipulation
But the MailMerge class also allows very detailed, code-level manipulation during the merge process. This includes handling merge events, customizing the merge process, and programmatically controlling the output of the merge operation. This level of control is essential for complex document generation scenarios that require fine-grained control over the merge process.
This article describes how to use the Field
To merge the template, we will use the following simplified JSON data.
[
{
"invoice-id": "1",
"invoice-date": "2019-01-01",
"line-items": [
{
"product-id": "1",
"quantity": "1",
"unit-price": "8"
},
{
"product-id": "2",
"quantity": "2",
"unit-price": "200"
},
{
"product-id": "3",
"quantity": "1",
"unit-price": "100"
},
{
"product-id": "4",
"quantity": "1",
"unit-price": "3"
}
]
}
]
In order to merge this template, the following code will be used:
textControl1.Load("template.tx", TXTextControl.StreamType.InternalUnicodeFormat);
MailMerge mailMerge = new MailMerge();
mailMerge.TextComponent = textControl1;
string jsonData = File.ReadAllText("data.json");
mailMerge.MergeJsonData(jsonData);
This results in the following merged document:
FieldMerged Event
Now let's attach the FieldMerged event to manipulate the merge process.
textControl1.Load("template.tx", TXTextControl.StreamType.InternalUnicodeFormat);
MailMerge mailMerge = new MailMerge();
mailMerge.TextComponent = textControl1;
mailMerge.FieldMerged += MailMerge_FieldMerged;
string jsonData = File.ReadAllText("data.json");
mailMerge.MergeJsonData(jsonData);
Each time a merge field is merged (successfully or not), this event is invoked. A Table
In this event, we check that the TableCell property is not null. If it is not null, we set the background color of the cell.
private void MailMerge_FieldMerged(object sender, MailMerge.FieldMergedEventArgs e)
{
if (e.TableCell != null)
{
e.TableCell.CellFormat.BackColor = Color.Red;
e.TableCell.CellFormat.BottomBorderWidth = 60;
e.TableCell.CellFormat.BottomBorderColor = Color.Blue;
}
}
As a result, all merged cells are colored during the merge process.
Dynamic Cell Colors
Let's make this process dynamic by adding some logic. The CellFilterInstructions class is used to compare a value with a given value to return a specific color.
using System;
using System.Drawing;
using System.Linq;
public class CellFilterInstructions
{
public double? CompareValue { get; set; } = null;
public RelationalOperator? Operator { get; set; } = null;
public Color TrueColor { get; set; } = Color.White;
public Color FalseColor { get; set; } = Color.White;
public enum RelationalOperator
{
Equals = 0,
NotEqual,
LessThan,
GreaterThan,
}
// evaluates the instruction and returns the proper color
public Color? GetColor(string value)
{
if (Double.TryParse(ParseToNumber(value), out double dValue) == true)
{
switch (Operator)
{
case RelationalOperator.Equals:
return (dValue == CompareValue ? TrueColor : FalseColor);
case RelationalOperator.NotEqual:
return (dValue != CompareValue ? TrueColor : FalseColor);
case RelationalOperator.GreaterThan:
return (dValue > CompareValue ? TrueColor : FalseColor);
case RelationalOperator.LessThan:
return (dValue < CompareValue ? TrueColor : FalseColor);
default:
return null;
}
}
else
return null;
}
private string ParseToNumber(string text)
{
var numericChars = "0123456789,.".ToCharArray();
return new String(text.Where(c => numericChars.Any(n => n == c)).ToArray());
}
}
The following code creates a new rule that returns green if the value is greater than 10 and red if it is not. This rule is serialized and stored in the Name property of a table cell.
textControl1.Load("template.tx", TXTextControl.StreamType.InternalUnicodeFormat);
CellFilterInstructions cellFilterInstructions = new CellFilterInstructions() {
CompareValue = 10,
Operator = CellFilterInstructions.RelationalOperator.GreaterThan,
TrueColor = Color.Green,
FalseColor = Color.Red
};
textControl1.Tables[1].Cells[2,2].Name =
JsonConvert.SerializeObject(cellFilterInstructions);
MailMerge mailMerge = new MailMerge();
mailMerge.TextComponent = textControl1;
mailMerge.FieldMerged += MailMerge_FieldMerged;
string jsonData = File.ReadAllText("data.json");
mailMerge.MergeJsonData(jsonData);
In the FieldMerged event, this rule is deserted and evaluated. The color returned is then applied to the Table
private void MailMerge_FieldMerged(object sender, MailMerge.FieldMergedEventArgs e)
{
// custom field handling
if (e.TableCell == null)
return;
if (e.TableCell.Name != "")
{
CellFilterInstructions instructions =
(CellFilterInstructions)JsonConvert.DeserializeObject(
e.TableCell.Name,
typeof(CellFilterInstructions));
// retrieve the color
Color? color = instructions.GetColor(e.MailMergeFieldAdapter.ApplicationField.Text);
// apply the color
if (color != null)
e.TableCell.CellFormat.BackColor = (Color)color;
}
}
The following screenshot shows the result of this merge process:
Conclusion
The MailMerge class in TX Text Control provides a powerful and flexible solution for automating document generation processes. Using merge blocks and code-level manipulation, developers can easily create dynamic, data-driven documents. The FieldMerged event provides fine-grained control over the merge process, allowing developers to customize output based on specific conditions. This level of control is essential for complex document generation scenarios that require precise handling of data and content.
Related Posts
Use MailMerge in .NET on Linux to Generate Pixel-Perfect PDFs from DOCX…
This article explores how to use the TX Text Control MailMerge feature in .NET applications on Linux to generate pixel-perfect PDFs from DOCX templates. This powerful combination enables…
Generating Dynamic NDAs Using TX Text Control MailMerge in C# .NET
This article demonstrates how to generate dynamic NDAs using TX Text Control MailMerge in C# .NET. It covers the process of creating a template, binding data, and generating the final document.
Designing a Maintainable PDF Generation Web API in ASP.NET Core (Linux) C#…
This article shows how to create a PDF generation Web API in ASP.NET Core on Linux using TX Text Control .NET Server. The clean architecture is used to create a maintainable and testable solution.
When to Generate Documents Server-Side Instead of Client-Side: A Focus on…
When it comes to document generation, deciding whether to handle the task server-side or client-side is a key architectural decision for any organization. This article discusses the benefits of…
Mail Merge: Inserting Merge Blocks using the DataSourceManager in C#
This article shows how to insert merge blocks into a document using the DataSourceManager class in C#. Merge blocks are used to repeat a block of content for each data record in a data source. The…