这篇文章参考自poi-tl、aspose实现word中表在每页携带表头表尾_poi-tl 表格超出纸张大小第二页任然需要表头-CSDN博客
先说一下目前所做的表格情况:检测项目是动态的,但是最后一行要求在最后填充整个页面

以前的我做法是:项目行的行高是固定的27.5,一页面大概就是25个项目行,最后备注行算还差多少行合并就行。
但是现在要改成
(1)项目行是自适应的,不能固定了,
(2)项目分页,每页要显示表头
所以我就只能判断整个页面表格能显示的最大高度,然后算项目行使用了多少高度,再进行填充
先看一下全部代码
cs
/// <summary>
/// 导出
/// </summary>
public static string SetReportExportTest(int type, M.agAgricul agModel, M.agReportTask taskModel, M.agReport reportModel, List<usPersonInfo>? personList, string folderPath, int? exportType)
{
Aspose.Words.Document doc = new Aspose.Words.Document("xxxxxxxxxxxx");
var builder = new DocumentBuilder(doc);
int index = 0;
int cellFixCout = 6;//一行6列
int nowIndex = 0;
if (taskModel.agReportDetail_FKs.Count > 0)
{
taskModel.agReportDetail_FKs.ForEach(j =>
{
int remarkRow = 0;//备注所在行
nowIndex++;
//插入分页符
//builder.InsertBreak(BreakType.SectionBreakNewPage);//会把页码截断
builder.InsertBreak(BreakType.PageBreak);
//插入纵页
builder.PageSetup.Orientation = Aspose.Words.Orientation.Portrait;
#region 格式(标题)
Aspose.Words.Font font = builder.Font;
font.Size = 14;
font.Bold = false;
font.Color = System.Drawing.Color.Black;
font.Name = "宋体";
ParagraphFormat paragraphFormat = builder.ParagraphFormat;
paragraphFormat.Alignment = ParagraphAlignment.Center;
paragraphFormat.KeepTogether = true;
#endregion
builder.Writeln("人类三体文明牛马质量检测处\r\n检验检测报告\r\n");
#region 格式(编号、名称)
builder.Font.Size = 10;
builder.Font.Name = "宋体";
builder.Font.Bold = false;
#endregion
var table = builder.StartTable();
builder.ParagraphFormat.ClearFormatting();
builder.InsertCell();
// 编号左对齐
builder.CellFormat.Width = 285; // 设置单元格宽度
builder.ParagraphFormat.Alignment = ParagraphAlignment.Left;
builder.Write($"编号:NM0000123");
// 名称右对齐
builder.InsertCell();
builder.CellFormat.Width = 285;
builder.ParagraphFormat.Alignment = ParagraphAlignment.Right;
builder.Write($"名称:牛马");
builder.EndRow();
builder.EndTable();
// 隐藏所有边框
table.SetBorders(Aspose.Words.LineStyle.None, 0, Color.Black);
// 开始构建表
Aspose.Words.Tables.Table tableNow = builder.StartTable();
#region 格式(表头)
//设置高度并定义标题行的高度规则。
builder.RowFormat.Height = 55;
builder.RowFormat.HeightRule = HeightRule.AtLeast;
builder.ParagraphFormat.ClearFormatting();
builder.ParagraphFormat.Alignment = ParagraphAlignment.Center;
int projectFontsize = 10;
builder.Font.Size = 11;
builder.Font.Name = "宋体";
builder.Font.Bold = false;
builder.CellFormat.VerticalAlignment = CellVerticalAlignment.Center;
//我们不需要指定此单元格的宽度,因为它是从前一个单元格继承的。
#endregion
//builder.RowFormat.HeadingFormat = true;
builder.InsertCell();
builder.Write("检测项目");
builder.InsertCell();
builder.Write("单位");
builder.InsertCell();
builder.Write("检测结果");
builder.InsertCell();
builder.Write("检测依据");
builder.InsertCell();
builder.Write("标准要求");
builder.InsertCell();
builder.Write("单项判定");
builder.InsertCell();
builder.Write("判断依据");
//调用以下方法结束行并开始新行。
builder.EndRow();
remarkRow++;
if (projects.Count > 0)
{
projects.ForEach(project =>
{
#region 格式(检测项目)
//设置高度并定义标题行的高度规则。
builder.RowFormat.Height = 27;
builder.RowFormat.HeightRule = HeightRule.AtLeast;
builder.ParagraphFormat.Alignment = ParagraphAlignment.Center;
builder.Font.Size = projectFontsize;
builder.Font.Name = "宋体";
builder.Font.Bold = false;
builder.CellFormat.VerticalAlignment = CellVerticalAlignment.Center;
//我们不需要指定此单元格的宽度,因为它是从前一个单元格继承的。
#endregion
builder.InsertCell();
builder.Write(project);
builder.InsertCell();
builder.Write("");
builder.InsertCell();
builder.Write("");
builder.InsertCell();
builder.Write("");
builder.InsertCell();
builder.Write("--- ---");
builder.InsertCell();
builder.Write("--- ---");
builder.InsertCell();
builder.Write("--- ---");
builder.EndRow();
remarkRow++;//备注行后移
});
}
//int allPageRows = 25;//去掉表头(5行)
//int finalRow = projects.Count + jcCount + 5 + 1;//整页使用了多少行(按25行的来算)5行:题头+检测项目(3行) 1行:备注所占行
//int n = finalRow / allPageRows > 0 ? (finalRow % allPageRows > 0 ? ((finalRow / allPageRows) + 1) : (finalRow / allPageRows)) : 1;
//int m = allPageRows * n - finalRow;//还有多少行填满一页
#region 格式化(备注行)
builder.ParagraphFormat.Alignment = ParagraphAlignment.Left;
builder.CellFormat.VerticalAlignment = CellVerticalAlignment.Top;
#endregion
builder.InsertCell();
builder.Write("以下空白");
for (int ii = 1; ii <= cellFixCout; ii++)
{
builder.InsertCell();
}
builder.EndRow();
#region 设置行高
//// 获取页面总高度
//double totalPageHeight = newSection.PageSetup.PageHeight;
//// 获取上下边距
//double topMargin = newSection.PageSetup.TopMargin;
//double bottomMargin = newSection.PageSetup.BottomMargin;
//// 计算可用高度(实际内容区域)
//int usableHeight = (int)(totalPageHeight - topMargin - bottomMargin);
////int usableHeight = 675;//(int)(totalPageHeight - topMargin - bottomMargin);
////double pageHeight = 540;//一页高675,项目20行共540,表头行55,题头80 110
//double usedHeight = tableNow.Rows.Select(h => (Aspose.Words.Tables.Row)h).Sum(h => h.RowFormat.Height) + 80;
//int nn = (int)(usedHeight / usableHeight > 0 ? (usedHeight % usableHeight > 0 ? ((usedHeight / usableHeight) + 1) : (usedHeight / usableHeight)) : 1);
//double mm = usableHeight * nn - usedHeight;//还有多少高填满一页
//var dsgds = ((Aspose.Words.Tables.Row)tableNow.Rows[remarkRow - 1]).RowFormat.Height;
//tableNow.Rows[remarkRow].RowFormat.Height = mm;
#endregion
#region 宽度赋值
//设置表格的首选宽度
tableNow.PreferredWidth = PreferredWidth.FromPoints(570); // 首选宽度,根据总宽度调整,没有设置就会导致只会按下面比例生成不可控的宽度
foreach (Aspose.Words.Tables.Row row in tableNow.Rows)
{
row.Cells[0].CellFormat.Width = 80;
row.Cells[1].CellFormat.Width = 60;
row.Cells[2].CellFormat.Width = 70;
row.Cells[3].CellFormat.Width = 105;
row.Cells[4].CellFormat.Width = 70;
row.Cells[5].CellFormat.Width = 70;
row.Cells[6].CellFormat.Width = 115;
}
#endregion
#region 合并
//备注行合并
for (int c = 0; c <= cellFixCout; c++)
{
if (c == 0)
{
tableNow.Rows[remarkRow].Cells[c].CellFormat.HorizontalMerge = Aspose.Words.Tables.CellMerge.First;
}
else
{
tableNow.Rows[remarkRow].Cells[c].CellFormat.HorizontalMerge = Aspose.Words.Tables.CellMerge.Previous;
}
}
#endregion
//表示我们已经完成了构建表的信号。
builder.EndTable();
#region 对动态表格进行题头、最后一行满页填充处理
doc.FirstSection.Body.AppendChild(tableNow);
doc.UpdatePageLayout();
int inddd = doc.GetChildNodes(NodeType.Table, true).IndexOf(tableNow);
Aspose.Words.Tables.Table tableNow22 = (Aspose.Words.Tables.Table)doc.GetChildNodes(NodeType.Table, true)[nowIndex * 2 + 1];
DealTableCopyRow(doc, nowIndex * 2 + 1);
#endregion
});
}
//导出类型(1pdf 2word)
string savePath = "";
if (exportType == 1)
{
savePath = "报告.pdf";
if (System.IO.File.Exists(savePath))
System.IO.File.Delete(savePath);
doc.Save(savePath, SaveFormat.Pdf);
}
if (exportType == 2)
{
savePath = "报告.doc";
if (System.IO.File.Exists(savePath))
System.IO.File.Delete(savePath);
doc.Save(savePath, SaveFormat.Doc);
}
return savePath;
}
效果如下:
一页的效果

多页的效果:

之前的做法是固定项目行高来算的
cs
int allPageRows = 25;//去掉表头(5行)
int finalRow = projects.Count + jcCount + 5 + 1;//整页使用了多少行(按25行的来算)5行:题头+检测项目(3行) 1行:备注所占行
int n = finalRow / allPageRows > 0 ? (finalRow % allPageRows > 0 ? ((finalRow / allPageRows) + 1) : (finalRow / allPageRows)) : 1;
int m = allPageRows * n - finalRow;//还有多少行填满一页
//备注行之后的空白行
for (int ii = 0; ii < m; ii++)
{
builder.InsertCell();
builder.InsertCell();
builder.InsertCell();
builder.InsertCell();
builder.InsertCell();
builder.InsertCell();
builder.InsertCell();
}
//合并备注行和空白行达到填充整页的目的
for (int r = remarkRow; r <= (remarkRow + m); r++)
{
for (int c = 0; c <= cellFixCout; c++)
{
if (r == remarkRow)//备注第一行
{
if (c == 0)
{
tableNow.Rows[r].Cells[c].CellFormat.VerticalMerge = Aspose.Words.Tables.CellMerge.First;
tableNow.Rows[r].Cells[c].CellFormat.HorizontalMerge = Aspose.Words.Tables.CellMerge.First;
}
else
{
tableNow.Rows[r].Cells[c].CellFormat.VerticalMerge = Aspose.Words.Tables.CellMerge.First;
tableNow.Rows[r].Cells[c].CellFormat.HorizontalMerge = Aspose.Words.Tables.CellMerge.Previous;
}
}
else
{
if (c == 0)//每行第一个单元格
{
tableNow.Rows[r].Cells[c].CellFormat.VerticalMerge = Aspose.Words.Tables.CellMerge.Previous;
tableNow.Rows[r].Cells[c].CellFormat.HorizontalMerge = Aspose.Words.Tables.CellMerge.First;
}
else
{
tableNow.Rows[r].Cells[c].CellFormat.VerticalMerge = Aspose.Words.Tables.CellMerge.Previous;
tableNow.Rows[r].Cells[c].CellFormat.HorizontalMerge = Aspose.Words.Tables.CellMerge.Previous;
}
}
}
}
想按照每行高度来算,然后发现在构建表中获取的行高都是预设的高度,不是实际高度,即需要获取渲染后的行高,由于我使用预设的行高27,直接使用RowFormat.Height来获取高度,只会获取到预设的27
cs
#region 格式(检测项目)
//设置高度并定义标题行的高度规则。
builder.RowFormat.Height = 27;
builder.RowFormat.HeightRule = HeightRule.AtLeast;
builder.ParagraphFormat.Alignment = ParagraphAlignment.Center;
builder.Font.Size = projectFontsize;
builder.Font.Name = "宋体";
builder.Font.Bold = false;
builder.CellFormat.VerticalAlignment = CellVerticalAlignment.Center;
//我们不需要指定此单元格的宽度,因为它是从前一个单元格继承的。
#endregion
builder.InsertCell();
builder.Write(project);
展示一下开始尝试的错误代码
cs
#region 设置行高
// 获取页面总高度
double totalPageHeight = newSection.PageSetup.PageHeight;
// 获取上下边距
double topMargin = newSection.PageSetup.TopMargin;
double bottomMargin = newSection.PageSetup.BottomMargin;
// 计算可用高度(实际内容区域)
int usableHeight = (int)(totalPageHeight - topMargin - bottomMargin);
//int usableHeight = 675;//(int)(totalPageHeight - topMargin - bottomMargin);
//调试出的大概数值就是:一页高675,项目20行共540,表头行55,题头80或110
//其实这里面是错误的,会随项目数的不同,题头的数值一直在变动,时而80,时而100
double usedHeight = tableNow.Rows.Select(h => (Aspose.Words.Tables.Row)h).Sum(h => h.RowFormat.Height) + 80;
int nn = (int)(usedHeight / usableHeight > 0 ? (usedHeight % usableHeight > 0 ? ((usedHeight / usableHeight) + 1) : (usedHeight / usableHeight)) : 1);
double mm = usableHeight * nn - usedHeight;//还有多少高填满一页
//设置备注行高度
tableNow.Rows[remarkRow].RowFormat.Height = mm;
#endregion
由于获取不到真实的项目行所占据的高度,导致导出的结果一直不是很理想
怎么获取构建表格行的真实高度?
其实这里所要获取的是基于实际渲染结果的精确行高
使用的主要代码如下
cs
doc.UpdatePageLayout(); // 必须调用,否则布局信息可能不准确
//建立文档节点与布局实体之间的映射关系
LayoutCollector collector = new LayoutCollector(doc);
//用于遍历和访问文档的布局实体(如页、行、单元格等)
LayoutEnumerator enumerator = new LayoutEnumerator(doc);
/* 定位到目标元素
* table.Rows[0].Cells[0].FirstParagraph: 获取表格第一行第一个单元格的第一个段落
* collector.GetEntity(): 通过收集器找到该段落对应的布局实体
* enumerator.Current =: 将枚举器设置到该布局实体
*/
enumerator.Current = collector.GetEntity(table.Rows[0].Cells[0].FirstParagraph);
//向上遍历直至找到ROW实体
while (enumerator.Type != LayoutEntityType.Row)
{
enumerator.MoveParent();
}
double Y = enumerator.Rectangle.Y;//以双精度返回框架矩形左上角的Y坐标。
double height = enumerator.Rectangle.Height;//以双精度返回框架矩形的高度。
这里解释一下
enumerator.Current = collector.GetEntity(table.Rows[0].Cells[0].FirstParagraph);这里定位当前枚举了,此时布局层级可能是
Paragraph (段落)
↳ Line (行)
↳ Span (文本范围)
↳ ...
所以需要向上遍历找到行,遍历过程可能是
开始: Paragraph (段落)
第一次 MoveParent(): Line (文本行)
第二次 MoveParent(): Cell (单元格)
第三次 MoveParent(): Row (表格行) ← 找到目标!
在构建完表之后调用处理方法(一定要builder.EndTable()之后)
cs
#region 对动态表格进行题头、最后一行满页填充处理
doc.FirstSection.Body.AppendChild(tableNow);
doc.UpdatePageLayout();
int inddd = doc.GetChildNodes(NodeType.Table, true).IndexOf(tableNow);
Aspose.Words.Tables.Table tableNow22 = (Aspose.Words.Tables.Table)doc.GetChildNodes(NodeType.Table, true)[nowIndex * 2 + 1];
DealTableCopyRow(doc, nowIndex * 2 + 1);
#endregion
具体的方法如下
cs
/// <summary>
/// 页面复制表头、填充满页处理
/// </summary>
/// <param name="tableN">文档中的第几个表格</param>
public static void DealTableCopyRow(Document doc ,int tableN)
{
//Document doc = new Document("testEndAddOutOnePage.docx");
Aspose.Words.Tables.Table table = doc.GetChildNodes(NodeType.Table, true)[tableN] as Aspose.Words.Tables.Table;
double tableHeadHeight = GetTableHeadHeight(doc, 1, tableN);//表头
//double tableTailHeight = GetTableTailHeight(doc, 4, tableN);//表尾
double tableHeightMax = GetTableHeightMax(doc);//word中table适配的最高高度
if (tableHeightMax == 0.0)
{
//需要处理的word文件不足一页 直接返回原文件
return;
}
double tableCommonRowHeight = GetTableCommonRowHeight(doc, 1, 0, tableN);//获取自匹配插入数据的大众行高
int commonRow = 0;//获取自匹配插入数据的大众行的代表行索引
int numRows = 0;//最后一页补充条数
LayoutCollector collector = new LayoutCollector(doc);//获取实际行高
int pages = 1;//标记是不是第一页
double sumHeight = 0;//手动记录总行高
int count = table.Rows.Count;//总行数
int tableHeadIndex = 0;//表头行索引
double ttHeadRowHeight = 95;//题头高度,有方法返回,但是我是调试出了一个具体的值,就直接用了
//循环跳过表头一行
for (int row = 1; row < count; row++)
{
string text = table.Rows[row].Cells[0].GetText();
double height = FindRowHeight(collector, row, table, doc);//以双精度返回框架矩形的实际高度
//第一页处理
if (pages == 1)
{
//跳过表头一行
//寻找第一个符合标准行的行,作为后续克隆的行
if (height == tableCommonRowHeight && commonRow == 0)
{
commonRow = row; //此时的row还未row++ 就是具体行的索引
}
sumHeight = sumHeight + height;
//该页已经满了如果加上次行后表尾位置不够 判断为不能插入到此页 调整上 一行 样式进行适配
//if (tableHeightMax - sumHeight - tableTailHeight < 0)
if (tableHeightMax - sumHeight - tableHeadHeight - ttHeadRowHeight < 0)
{
double proRowHeight = FindRowHeight(collector, row - 1, table, doc);//获取到上行的行高
table.Rows[row - 1].RowFormat.Height = proRowHeight + (tableHeightMax - sumHeight - tableHeadHeight - ttHeadRowHeight) + height;
#region 插入表头一行
Node node = table.Rows[0].Clone(true);
table.Rows.Insert(row, node);//插入到第几行上方 因为刚刚说明过是多加了 所以这里把表尾加到此行上方是正确的
row++;//插入航后 指针也要相应的向下移动
count++;//总行数也跟着增加
#endregion
sumHeight = height;//表尾没有空间将这行放下 所以需要放在下一页
pages++;
}
}
else//后续页处理
{
sumHeight = sumHeight + height;
//该页已经满了如果加上次行后表尾位置不够 判断为不能插入到此页 调整上一行样式进行适配
if (tableHeightMax - sumHeight - tableHeadHeight < 0)
{
double proRowHeight = FindRowHeight(collector, row - 1, table, doc);//获取到上行的行高
table.Rows[row - 1].RowFormat.Height = proRowHeight + (tableHeightMax - sumHeight - tableHeadHeight) + height;
#region 插入表头一行
Node node = table.Rows[tableHeadIndex].Clone(true);
table.Rows.Insert(row, node);//插入到第几行上方 因为刚刚说明过是多加了 所以这里把表尾加到此行上方是正确的
doc.UpdatePageLayout();
row++;//插入航后 指针也要相应的向下移动
count++;//总行数也跟着增加
#endregion
sumHeight = height;//表尾没有空间将这行放下 所以需要放在下一页
pages++;
}
}
}
//最后一页填充逻辑
if (pages == 1)
{
//第一页不同的是多了个题头
double residuePlace = tableHeightMax - sumHeight - tableHeadHeight - ttHeadRowHeight;//剩余空间=总高度-项目行总高-表头高-题头高
double proRowHeight = FindRowHeight(collector, count - 1, table, doc);//获取到上行的行高
table.Rows[count - 1].RowFormat.Height = proRowHeight + (tableHeightMax - sumHeight - tableHeadHeight);
}
else
{
double residuePlace = tableHeightMax - sumHeight - tableHeadHeight;//最后一页剩余空间
double proRowHeight = FindRowHeight(collector, count - 1, table, doc);//获取到上行的行高
table.Rows[count - 1].RowFormat.Height = proRowHeight + (tableHeightMax - sumHeight - tableHeadHeight);
}
collector.Clear();
doc.UpdatePageLayout();//更新布局
}
cs
/// <summary>
/// 根据传入表计算表头总高度
/// </summary>
/// <param name="doc"></param>
/// <param name="tableHead">表头行数</param>
/// <param name="tableN">第几个表</param>
/// <returns></returns>
public static double GetTableHeadHeight(Document doc, int tableHead, int tableN)
{
var lsittables= doc.GetChildNodes(NodeType.Table, true);
Aspose.Words.Tables.Table table = (Aspose.Words.Tables.Table)doc.GetChildNodes(NodeType.Table, true)[tableN] ;
//表头总高度
double headHigh = 0;
//获取实际行高
LayoutCollector collector = new LayoutCollector(doc);
LayoutEnumerator enumerator = new LayoutEnumerator(doc);
int count = 0;
//for (Aspose.Words.Tables.Row row : table.Rows)
for (int i = 0; i < table.Rows.Count; i++)
{
enumerator.Current = collector.GetEntity(table.Rows[i].Cells[0].FirstParagraph);
//在每一层中寻找row类型的实际参数
while (enumerator.Type != LayoutEntityType.Row)
{
enumerator.MoveParent();
}
//以双精度返回框架矩形左上角的Y坐标。
double Y = enumerator.Rectangle.Y;
//以双精度返回框架矩形的高度。
double height = enumerator.Rectangle.Height;
if (count < tableHead)
{
headHigh = headHigh + height;
}
else
{
break;
}
count++;
}
return headHigh;
}
cs
/// <summary>
/// 获取表格在任意一页中占据的最大实际高度
/// </summary>
/// <param name="doc"></param>
/// <param name="tableHead">表头行数</param>
/// <returns></returns>
public static double GetTableHeightMax(Document doc)
{
//页面高度包括了上下边框、页眉页脚高度和内容高度
double sumHeightMax = 0;//每页最大行数
Section newSection = doc.LastSection;
// 获取页面总高度
double totalPageHeight = newSection.PageSetup.PageHeight;
// 获取上下边距
double topMargin = newSection.PageSetup.TopMargin;
double bottomMargin = newSection.PageSetup.BottomMargin;
// 主要页眉
double headerHeight = GetHeaderHeight(doc);
//主要页脚
double footerHeight = GetFooterHeight(doc);
// 计算可用高度(实际内容区域)
sumHeightMax = totalPageHeight - topMargin - bottomMargin - headerHeight - footerHeight;
return sumHeightMax;
}
cs
/// <summary>
/// 获取页眉页脚的实际高度
/// </summary>
public static double GetHeaderFooterHeight(Aspose.Words.HeaderFooter headerFooter, Document doc)
{
doc.UpdatePageLayout();
LayoutCollector collector = new LayoutCollector(doc);
try
{
LayoutEnumerator enumerator = new LayoutEnumerator(doc);
enumerator.Current = collector.GetEntity(headerFooter);
// 向上查找直到找到HeaderFooter的布局实体
while (enumerator.Type != LayoutEntityType.HeaderFooter && enumerator.Type != LayoutEntityType.None)
{
if (!enumerator.MoveParent()) break;
}
if (enumerator.Type == LayoutEntityType.HeaderFooter)
{
return enumerator.Rectangle.Height;
}
}
catch
{
// 如果无法获取实际高度,返回估算值
}
// 估算高度:根据内容行数估算
int lineCount = 0;
foreach (Paragraph para in headerFooter.GetChildNodes(NodeType.Paragraph, true))
{
if (!string.IsNullOrEmpty(para.GetText().Trim()))
{
lineCount++;
}
}
return lineCount * 16; // 每行大约16点
}
/// <summary>
/// 获取页眉高度
/// </summary>
public static double GetHeaderHeight(Document doc)
{
double headerHeight = 0;
foreach (Section section in doc.Sections)
{
if (section.HeadersFooters[HeaderFooterType.HeaderPrimary] != null)
{
// 需要更新布局后获取实际高度
doc.UpdatePageLayout();
LayoutCollector collector = new LayoutCollector(doc);
var header = section.HeadersFooters[HeaderFooterType.HeaderPrimary];
if (header != null && header.GetChildNodes(NodeType.Any, false).Count > 0)
{
// 估算或获取实际高度
headerHeight = Math.Max(headerHeight, GetHeaderFooterHeight(header, doc));
}
}
}
return headerHeight;
}
/// <summary>
/// 获取页脚高度
/// </summary>
public static double GetFooterHeight(Document doc)
{
double footerHeight = 0;
foreach (Section section in doc.Sections)
{
if (section.HeadersFooters[HeaderFooterType.FooterPrimary] != null)
{
var footer = section.HeadersFooters[HeaderFooterType.FooterPrimary];
if (footer != null && footer.GetChildNodes(NodeType.Any, false).Count > 0)
{
footerHeight = Math.Max(footerHeight, GetHeaderFooterHeight(footer, doc));
}
}
}
return footerHeight;
}
还有俩个方法没怎么用上,自行斟酌选用
cs
/// <summary>
/// 获取首页除表格外的题头等所占高度
/// </summary>
/// <param name="doc"></param>
/// <param name="tableHead">表头行数</param>
/// <returns></returns>
public static double GetPageTitleHeight(Document doc, double tablePageMax)
{
double titleHeight = 0;
Section newSection = doc.LastSection;
// 获取页面总高度
double totalPageHeight = newSection.PageSetup.PageHeight;
// 获取上下边距
double topMargin = newSection.PageSetup.TopMargin;
double bottomMargin = newSection.PageSetup.BottomMargin;
// 计算可用高度(实际内容区域)
int usableHeight = (int)(totalPageHeight - topMargin - bottomMargin);
//int usableHeight = 675;//(int)(totalPageHeight - topMargin - bottomMargin);
titleHeight = usableHeight - tablePageMax;
return titleHeight;
}
/// <summary>
/// 获取表格中自动匹配list数据中普通行的行高
/// </summary>
/// <param name="doc"></param>
/// <param name="tableHead">表头</param>
/// <param name="tableTail">表尾</param>
/// <param name="tableN"></param>
/// <returns></returns>
public static double GetTableCommonRowHeight(Document doc, int tableHead, int tableTail, int tableN)
{
Aspose.Words.Tables.Table table = doc.GetChildNodes(NodeType.Table, true)[tableN] as Aspose.Words.Tables.Table; ;
int rows = table.Rows.Count;
//获取实际行高
LayoutCollector collector = new LayoutCollector(doc);
LayoutEnumerator enumerator = new LayoutEnumerator(doc);
List<Double> heightList = new List<Double>();
for (int i = tableHead - 1; i < rows - tableTail; i++)
{
enumerator.Current = collector.GetEntity(table.Rows[i - 1].Cells[0].FirstParagraph);
//enumerator.setCurrent(collector.getEntity(table.getRows().get(i - 1).getFirstCell().getFirstParagraph()));
//在每一层中寻找row类型的实际参数
while (enumerator.Type != LayoutEntityType.Row)
{
enumerator.MoveParent();
}
//以双精度返回框架矩形的高度。
double height = enumerator.Rectangle.Height;
heightList.Add(height);
// System.out.println("\n高度: " + height + "\n" +
// "第" + i + "\n内容:" + table.getRows().get(i-1).getText());
}
// 使用LINQ来按元素分组,并计算每个元素的出现次数
var elementCountMap = heightList
.GroupBy(h => h)
.ToDictionary(g => g.Key, g => g.LongCount());
// 找出出现次数最多的元素
var max = elementCountMap
.OrderByDescending(pair => pair.Value)
.FirstOrDefault();
// 获取key
double key = max.Key;
//// 使用Collectors.groupingBy来按元素分组,并计算每个元素的出现次数
//Map<Double, Long> elementCountMap = heightList.stream()
// .collect(Collectors.groupingBy(Function.identity(), Collectors.counting()));
//// 找出出现次数最多的元素
//Optional<Map.Entry<Double, Long>> max = elementCountMap.entrySet().stream()
// .max(Map.Entry.comparingByValue());
////获取key
//Double key = max.get().getKey();
return key;
}
再展示一下多页的效果
