@rose.thomas
Summary
Aspose.Words does not provide a special tag for page breaks inside a mail‑merge table. To start each group of rows on a new page you must insert a break programmatically—either by adding a paragraph break after the table or by setting RowFormat.PageBreakBefore on the first row of the next group.
Why it happens
- The template contains only the repeatable region (
<<TableStart:…>> … <<TableEnd:…>>).
- During
ExecuteWithRegions Aspose.Words simply repeats the rows; it does not add any pagination logic.
- Therefore a page break has to be added explicitly after the rows of each group (or before the first row of the next group).
What to do next
Below is a self‑contained C# example (compatible with recent Aspose.Words versions) that shows two ways to achieve the required pagination.
using System;
using System.Collections.Generic;
using System.Linq;
using Aspose.Words;
using Aspose.Words.Tables;
class Program
{
// Sample data class
public class Employee
{
public string CompanyName { get; set; }
public string Name { get; set; }
public string Position { get; set; }
}
static void Main()
{
// 1. Load the template that contains a repeatable region:
// <<TableStart:Employees>>
// <<CompanyName>> <<Name>> <<Position>>
// <<TableEnd:Employees>>
Document doc = new Document("TemplateWithTable.docx");
// 2. Prepare source data
List<Employee> employees = GetSampleData();
// 3. Group rows by CompanyName
var groups = employees.GroupBy(e => e.CompanyName).ToList();
// 4. Locate the table that holds the repeatable region
Table table = (Table)doc.GetChild(NodeType.Table, 0, true);
// 5. Keep a copy of the placeholder row (the row that contains the merge fields)
Row placeholder = table.Rows[0];
placeholder.Remove(); // we will recreate rows ourselves
DocumentBuilder builder = new DocumentBuilder(doc);
// 6. Fill the table group by group
for (int g = 0; g < groups.Count; g++)
{
foreach (var emp in groups[g])
{
Row newRow = (Row)placeholder.Clone(true);
newRow.Cells[0].Paragraphs[0].Append(emp.CompanyName);
newRow.Cells[1].Paragraphs[0].Append(emp.Name);
newRow.Cells[2].Paragraphs[0].Append(emp.Position);
table.Rows.Add(newRow);
}
// 7. Insert a page break after the current group (skip after the last group)
if (g < groups.Count - 1)
{
// Option A – insert a break paragraph after the table
builder.MoveTo(table.LastRow);
builder.Writeln(); // start a new paragraph
builder.InsertBreak(BreakType.PageBreak);
// Option B – make the first row of the next group start on a new page
// Uncomment the line below and comment out the block above if you prefer this method.
// table.Rows.Last.RowFormat.PageBreakBefore = true;
}
}
// 8. Save the result
doc.Save("Report_With_PageBreaks.docx");
}
static List<Employee> GetSampleData() => new List<Employee>
{
new Employee { CompanyName = "Alpha Ltd", Name = "John", Position = "Manager" },
new Employee { CompanyName = "Alpha Ltd", Name = "Anna", Position = "Analyst" },
new Employee { CompanyName = "Beta Inc", Name = "Mike", Position = "Developer" },
new Employee { CompanyName = "Beta Inc", Name = "Sara", Position = "Tester" },
new Employee { CompanyName = "Gamma Co", Name = "Tom", Position = "Lead" }
};
}
Alternative: use a dummy merge field as a page‑break placeholder
If you prefer to keep the whole process inside ExecuteWithRegions, add a dummy field inside the repeatable region:
<<TableStart:Employees>>
<<CompanyName>> <<Name>> <<Position>> <<PageBreak>>
<<TableEnd:Employees>>
Then supply a field‑merging callback that replaces the placeholder with a real break:
class PageBreakCallback : IFieldMergingCallback
{
public void FieldMerging(FieldMergingArgs args)
{
if (args.FieldName == "PageBreak")
{
DocumentBuilder builder = new DocumentBuilder(args.Document);
builder.MoveToMergeField("PageBreak");
builder.InsertBreak(BreakType.PageBreak);
args.Text = string.Empty; // remove the placeholder field from output
}
}
public void ImageFieldMerging(ImageFieldMergingArgs args) { }
}
// Usage
doc.MailMerge.FieldMergingCallback = new PageBreakCallback();
doc.MailMerge.ExecuteWithRegions(dataSource);
Next steps for you
- Pick a strategy – manual row creation (first code block) or placeholder field with a callback (alternative).
- Add the LINQ grouping to your existing data‑preparation code.
- Insert the page break using the method you selected (Option A or Option B).
- Run the program and verify that each company’s rows start on a new page.
If you encounter an exception (e.g., ArgumentOutOfRangeException when accessing table.Rows[0]), confirm that the template indeed contains a table and that the placeholder row is the first row after the <<TableStart>> tag. Adjust the row index accordingly.
I could not fully verify this explanation against the retrieved sources. Please double-check the behaviour in your environment and confirm the exact SDK/version.