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