Hi Nicolas,
Here is what I was thinking, let’s say you have something like this dummy document as a result of the mail merge:
var document = new DocumentModel();
var section = new Section(document);
document.Sections.Add(section);
var table = new Table(document);
section.Blocks.Add(table);
var random = new Random();
for (int i = 0; i < 60; i++)
{
var row = new TableRow(document,
new TableCell(document,
new Paragraph(document,
string.Join("\n", Enumerable.Repeat("Sample", random.Next(1, 4))))),
new TableCell(document,
new Paragraph(document,
(random.NextDouble() * 1000).ToString())));
row.RowFormat.AllowBreakAcrossPages = false;
table.Rows.Add(row);
}
document.Save("Output.docx");
The table has rows with the first cell that has a random number of lines (for a dynamic row height) and the second cell with some numerical value.
Here is the screenshot:
Now what we could do is add PAGE Field to each TableRow, update their value with GemBox.Document’s rendering engine, split the Table accordingly, and separate each Table with the Paragraph that has a floating TextBox for a subtotal.
So, something like this:
var document = DocumentModel.Load("Output.docx");
var section = document.Sections[0];
var mainTable = (Table)section.GetChildElements(false, ElementType.Table).First();
var tableIndex = section.Blocks.IndexOf(mainTable);
// Add PAGE fields at the beginning of each row.
var mainRows = mainTable.Rows;
var pageField = new Field(document, FieldType.Page);
foreach (var row in mainRows)
row.Content.Start.InsertRange(pageField.Content);
// Update PAGE fields.
document.GetPaginator(new PaginatorOptions() { UpdateFields = true });
// Split the table into multiple tables based on the PAGE fields in the rows.
int currentRowIndex = 0;
string previousRowPage = "1";
double currentSubtotal = 0;
double total = 0;
TableRowCollection splitRows = null;
while (currentRowIndex < mainRows.Count)
{
var currentRow = mainRows[currentRowIndex];
var currentField = currentRow.GetChildElements(true, ElementType.Field).First();
var currentRowPage = currentField.Content.ToString();
// Create paragraph with subtotal and new table after it.
if (currentRowPage != previousRowPage)
{
var subtotalParagraph = new Paragraph(document,
new TextBox(document,
new FloatingLayout(
new HorizontalPosition(70, LengthUnit.Point, HorizontalPositionAnchor.Page),
new VerticalPosition(800, LengthUnit.Point, VerticalPositionAnchor.Page),
new Size(200, 25))
{
WrappingStyle = TextWrappingStyle.InFrontOfText
},
new Paragraph(document, "Subtotal: " + currentSubtotal.ToString())))
{
CharacterFormatForParagraphMark = { Size = 1 },
ParagraphFormat = { SpaceAfter = 0, SpaceBefore = 0, LineSpacing = 1 }
};
var splitTable = mainTable.Clone(false);
splitRows = splitTable.Rows;
section.Blocks.Insert(++tableIndex, subtotalParagraph);
section.Blocks.Insert(++tableIndex, splitTable);
previousRowPage = currentRowPage;
currentSubtotal = 0;
}
// Remove PAGE field.
currentField.Content.Delete();
// Add to subtotal.
var value = double.Parse(currentRow.Cells[1].Content.ToString());
currentSubtotal += value;
total += value;
// Move row to new table.
if (splitRows != null)
{
splitRows.Add(currentRow.Clone(true));
mainRows.RemoveAt(currentRowIndex);
}
else
{
++currentRowIndex;
}
}
section.Blocks.Insert(++tableIndex, new Paragraph(document, "Total: " + total.ToString()));
document.Save("OutputWithSubtotals.docx");
Here is the screenshot:
I hope this helps.
Regards,
Mario