TX Text Control .NET for Windows Forms

Conditional Content

Topic

A reminder that appears only on unpaid invoices, a clause that only some contracts contain, a shipping note that depends on the order total: conditional content keeps one template for all these variants. TX Text Control puts most of these decisions into the template itself, where users of the Reporting tab can see and change them, so the merge code stays the same. IF fields choose between two texts, merge blocks include or leave out whole sections, block conditions and filters act on records, and events of MailMerge handle what the template can't express.

Every example merges the invoice template invoice.docx of Merge Data into Fields with invoice.json. Filters for single rows of a block are covered in Sorting and Filtering.

Choose a Technique

ToUseWhere the rule lives
Insert one of two texts depending on a valueAn IF fieldTemplate
Include a section only when its data existsA merge block bound to an object or an arrayTemplate
Merge a nested block only when its parent record meets a conditionThe block's merging conditionTemplate
Leave out single rows of a blockFilter instructions of the blockTemplate
Include or leave out a subtemplateAn INCLUDETEXT field and the IncludeTextMerging eventTemplate and code
Change a merged value with your own logicThe FieldMerged eventCode

Rules in the template travel with it: the merge code of your application doesn't change when a user adds a condition.

Insert IF Fields

An IF field compares the value of a merge field with a second value and inserts one of two texts. Its MS Word field code has the form IF Expression1 Operator Expression2 TrueText FalseText, where Expression1 is the name of a merge field. The operators are equal to, not equal to, greater than, less than, greater than or equal to and less than or equal to.

The examples need an amount to compare. Add an AmountDue and a DueDate property to the invoice in invoice.json:

[
  {
    "Company": "Contoso Ltd.",
    "Name": "Jane Miller",
    "InvoiceNumber": "INV-1001",
    "AmountDue": 780.00,
    "DueDate": "2026-10-31",
    "Items": [
      { "Description": "Consulting", "Quantity": 2, "Price": 150.00 },
      { "Description": "Training", "Quantity": 1, "Price": 480.00 }
    ]
  }
]

In the Reporting tab, users insert the field from the Insert Special Field drop-down of the Merge Fields group with IF. The dialog box asks for the field name, the comparison, the value to compare with and the two texts:

The If Field Options dialog box with the field name company, the comparison Equals, the value Text Control and the texts True and False.

In code, the IfField class creates the field. Add using TXTextControl.DocumentServer.Fields; to Form1.cs and this handler:

private void insertIfFieldButton_Click(object sender, EventArgs e)
{
    IfField ifField = new IfField
    {
        Expression1 = "AmountDue",   // the name of a merge field
        Operator = IfField.RelationalOperator.GreaterThan,
        Expression2 = "0",
        TrueText = "Please pay the amount due by the due date.",
        FalseText = "Thank you, this invoice has been paid."
    };

    textControl1.ApplicationFields.Add(ifField.ApplicationField);
}

The code works as follows:

  • Expression1 names the merge field whose value is compared, and Expression2 is the value it is compared with.
  • Operator is Equals, NotEqual, LessThan, GreaterThan, GreaterThanOrEqualTo or LessThanOrEqualTo.
  • TrueText is inserted when the comparison is true, FalseText when it is false.
  • DataSourceCulture sets the culture used to compare numbers; the default is the culture of the current thread.

With AmountDue at 780.00, the merged invoice asks for payment. The inserted text takes the formatting of the field. In a merge block, an IF field is evaluated for each record, so a cell of an item table can show a note only for some items. Templates from MS Word keep IF fields as MS Word fields; load them with ApplicationFieldFormat.MSWord, as the merge code of Getting Started does.

Include Optional Sections

A merge block doesn't have to repeat. A block bound to a nested object is merged once when the object exists and removed with its content when the data doesn't contain it, because RemoveEmptyBlocks is true by default; set it to false to keep such blocks. The same applies to a block whose array is empty or missing. A block can hold complete clauses, tables, images or footnotes.

A contract template, for example, has a block for each optional clause, named like an object of the data:

[
  {
    "company": "Acme Corporation",
    "section_term": { "months": 24 },
    "section_compete": { "months": 12 }
  }
]

When a contract's data has no section_compete, the clause isn't in the document and the following text moves up. To keep numbered clauses intact, the blog article Generating Dynamic NDAs Using TX Text Control MailMerge in C# .NET builds each optional section as a block. Merge Blocks shows how to insert blocks for objects.

A table header row outside a block stays when the block is removed; make the header row part of the block so that the whole table disappears.

Merge a Block Only for Matching Parent Records

In master-detail data, a nested block can depend on its parent record: articles are listed only for orders above an amount, a note only for products that aren't available. The block's BlockMergingCondition holds this condition. It is stored with the block in the template, so the merge code needs nothing special. Sorting and Filtering sets one, and the blog article MailMerge: Rendering Conditional Table Rows shows a note row for products that aren't available.

Include Subtemplates Depending on Your Code

An INCLUDETEXT field includes a subtemplate, and a handler of the IncludeTextMerging event can replace what it includes. Assigning an empty document leaves the subtemplate out, for example the terms and conditions when a flag of your application says so. Supply Subtemplates From Code shows the handler and how to decide per record.

Change a Merged Value in Code

Decisions a template can't express go into a handler of the FieldMerged event. Its DataRow holds the whole record, so one field can depend on another. This handler shows "Paid" instead of the due date when nothing is due; it needs using System.Globalization;:

mailMerge.FieldMerged += (s, args) =>
{
    // Show "Paid" instead of the due date when nothing is due
    if (args.MailMergeFieldAdapter is MergeField mergeField &&
        mergeField.Name == "DueDate" &&
        args.DataRow != null &&
        Convert.ToDecimal(args.DataRow["AmountDue"], CultureInfo.InvariantCulture) == 0)
    {
        mergeField.ApplicationField.Text = "Paid";
    }
};

The property that holds the field is MailMergeFieldAdapter in the compiled assembly; the reference documents it on the page of FieldMergedEventArgs. Merge Events describes the other members of the event.

Remove What Stays Empty

Optional content can leave traces: an empty line where an address line had no data, or a placeholder image without an image. Five properties of MailMerge clean up the result:

PropertyRemovesDefault
RemoveEmptyFieldsMerge fields without datatrue
RemoveEmptyBlocksMerge blocks without data, with their contenttrue
RemoveEmptyLinesLines that are empty after the mergefalse
RemoveEmptyImagesImage placeholders without datafalse
RemoveTrailingWhitespaceTrailing whitespace, before the document is savedtrue

Conditional Instructions Are for Forms

TX Text Control also has conditional instructions, rules that change form fields while a user fills in a form, such as disabling a drop-down list while another field has no value. They act on form fields in the editor, not on the merge. Form Fields and Conditional Instructions describes them.

Next Steps