Products Technologies Demo Docs Blog Support Company

Merging Merge Block Cells Vertically with Matching Content

A merge block repeats defined content and merge fields based on given data rows of a specific child table or object. This demo shows how to vertically merge table cells in case the content is the same.

Merging Merge Block Cells Vertically with Matching Content

Merge blocks repeat content and included merge fields based on given data rows of a specific child table or object. Content within this block can be filtered and sorted with build-in functionality of the MailMerge class. This demo shows how to vertically merge table cells in case the content is the same.

Sample Merge Block

Consider the following merge block template:

Merge Block

After merging some data into this block, the MailMerge class produces the following output:

Merge Block

In a post-merge process, the vertically adjacent cells with the same content should be merged as shown in the next illustration:

Merge Block

Mark Merge Block Tables

In a first step, a BlockRowMerged event is attached to mark the resulting tables of merge blocks. In a later process, we will search for these tables to process them:

// merge data
using (TXTextControl.DocumentServer.MailMerge mm =
  new TXTextControl.DocumentServer.MailMerge()) {
  mm.TextComponent = textControl1;
  mm.BlockRowMerged += Mm_BlockRowMerged;
  mm.MergeObject(report);
}

In that event, the first cell is marked with the Name block_identifier.

private void Mm_BlockRowMerged(
        object sender,
        TXTextControl.DocumentServer.MailMerge.BlockRowMergedEventArgs e) {
                        
  using (TXTextControl.ServerTextControl tx = new TXTextControl.ServerTextControl()) {
    tx.Create();
    tx.Load(e.MergedBlockRow, TXTextControl.BinaryStreamType.InternalUnicodeFormat);

    // find all tables in a block and flag cell 1,1
    if (tx.Tables.GetItem() != null) {
      tx.Tables.GetItem().Cells.GetItem(1, 1).Name = "block_identifier";
    }

    byte[] data;

    tx.Save(out data, TXTextControl.BinaryStreamType.InternalUnicodeFormat);
    e.MergedBlockRow = data;
  }

}

After the MergeObject method created the document, we look for all tables with the table marker and call the MergeSimilarCells method:

// loop through all tables, find flagged block tables
// and pass them to "MergeSimilarColumns"
foreach (TXTextControl.Table table in FindBlockTables(textControl1)) {
  MergeSimilarColumns(table);
}

Comparing the Cells

The actual work is done in the MergeSimilarCells method that loops through all columns separately to find similar vertically adjacent cells with the same content. If cells are found with the same content, they are vertically merged and the cell's text is replaced with the common content.

private bool MergeSimilarCells(TXTextControl.Table table, bool firstIteration = true) {
                        
  // loop through all column separately
  foreach (TXTextControl.TableColumn col in table.Columns) {

    bool bMergeFlag = false;
    int iFirstRow = 0;
    string sCommonCellText = "";

    // row by row
    for (int row = 1; row <= table.Rows.Count; row++) { 

      // only cells that are not merged
      if (table.Cells[row, col.Column].Length != -1) {

        // if table cell contains text from previous cell
        // set "bMergeFlag" to true and flag row number
        if (table.Cells[row, col.Column].Text == sCommonCellText) {
          if (bMergeFlag == false) iFirstRow = row;
          bMergeFlag = true;
        }
        // if text is different and "bMergeFlag" is true, merge cells
        else if (bMergeFlag == true) {
          MergeCells(table, iFirstRow - 1, col.Column, row - 1, col.Column, sCommonCellText);
          bMergeFlag = false;
        }

        // if flag "bMergeFlag" is true and it is the last row, merge cells
        if (bMergeFlag == true &&
          row == table.Rows.Count &&
          table.Cells[row, col.Column].Text == sCommonCellText) {
          MergeCells(table, iFirstRow - 1, col.Column, row, col.Column, sCommonCellText);
        }

        // remember current cell text
        if (row < table.Rows.Count)
          sCommonCellText = table.Cells[row, col.Column].Text;

      }

    }
  }

  // two iterations required as rows are potentially merged
  if (firstIteration == true)
    MergeSimilarCells(table, false);

  return false;
}

// this method simply merges given cells and sets the common cell text
private void MergeCells(
  TXTextControl.Table table,
  int startRow,
  int startColumn,
  int stopRow,
  int stopColumn,
  string newText) {

  table.Select(startRow, startColumn, stopRow, stopColumn);
  table.MergeCells();
  table.Cells[startRow, startColumn].Text = newText;
}

This method must loop through the table twice (the function calls itself at the end) as complete rows are potentially merged which could result in more adjacent cells with the same content.

Merge Block

If the data is changed, so that cells in the columns Quantity and Price match, results look similar to the table shown in the next screenshot:

Merge Block

The vertical text alignment can be changed in the template, so that the merged table content is rendered in the middle of the table cell to generate a more readable layout:

Merge Block

Sample Project

This sample shows the flexibility of the MailMerge functionality. At any point, it is possible to interact during the merge process using the events or it is possible to manipulate the document after the merge process is finished.

Test this on your own by looking at the sample that is hosted in our GitHub account. This demo uses the Windows Forms version, but the code works with WPF and ASP.NET as well.

Stay in the loop!

Subscribe to the newsletter to receive the latest updates.

GitHub

Download and Fork This Sample on GitHub

We proudly host our sample code on github.com/TextControl.

Please fork and contribute.

Download ZIP

Open on GitHub

Open in Visual Studio

Requirements for this sample

  • Visual Studio 2019
  • TX Text Control .NET for Windows Forms (trial sufficient)

Related Posts

ASP.NETWindows FormsMail Merge

Table Extension: Remove Empty Columns After Mail Merge

When you use mail merge to merge repeating blocks, you may end up with blank columns if no data exists for a particular column. Removing empty columns from a table is demonstrated in this example.


ASP.NETWindows FormsASP.NET Core

Splitting Tables at Bookmark Positions and Cloning Table Headers

This article shows how to split tables at bookmark positions and how to clone table headers in TX Text Control .NET for Windows Forms and TX Text Control .NET Server.


ASP.NETWindows FormsExcel

Loading and Processing Excel XLSX Spreadsheet Tables into TX Text Control…

TX Text Control provides a powerful API to load and process Excel spreadsheet tables in .NET applications. This article shows how to load an Excel file and process the tables using TX Text Control…


ASP.NETWindows FormsTab Stops

Text to Table and Table to Text in TX Text Control and C#

TX Text Control provides powerful table features and also full access to text formatting which can be used to create tables from text and vice versa. This article shows how to convert text to…


ASP.NETWindows FormsWPF

Inserting MergeBlocks with the DataSourceManager and Applying Table Styles in C#

This article shows how to insert MergeBlocks with the DataSourceManager and how to apply table styles to those tables. The article uses the DocumentServer class to insert MergeBlocks with the…