输出到[Word]文档时如何在SSRS(RDLC Report)的每一页上重复table组header?
How to repeat table group header on every page in SSRS(RDLC Report) when outputting to [Word] Documents?
如MS Documenation所述:
Word does not repeat header rows on page two and greater, although you
set the RepeatOnNewPage property of the static header row in a tablix
(table, matrix, or list) to True. You can define explicit page breaks
in your report to force header rows to appear on new pages. However,
because Word applies its own pagination to the rendered report
exported to Word, results might vary and the header row might not
repeat predictably. The static header row is the row that contains the
column headings.
- 在每一页上重复组 Header 仅适用于 PDF 文档
- Word 文档只能在组间重复
那么RDLC报表输出到Word文档时,如何在每一页重复headers组呢?
此解决方案使用 OpenXML 作为文档处理。
谁也可能觉得这有帮助
- 输出带有动态部分的Word文档Header
- 将 SSRS 报告端口打开 XML 文件类型,例如 docm、dotx、dotm...
限制:
- 只支持XML格式的文件(.docx for SSRS),受限于Open XML
- 报告大小 <~= 32MB(文本),受 docx 格式限制
- 报告生成时间成本增加
- 如果同一报告需要提供 .PDF 格式
,则需要对 header 执行额外的逻辑
- tableheader消耗Header节
- 字段数据导致字段增长时的对齐问题
假设:
- 您已经在 Tablix 中成功准备了分组数据
- 数据组之间的分页已经完成
解法总结:
- 使用特定的标识符准备报告,header出现在每一页
- 在 .DOCX
中呈现报告
- 准备替换数据
- 使用 OpenXML
打开报告
- 准备部分Header
- 找到记录组之间的Page Break并替换为Section Break
- 相应地将部分 header 绑定到每个部分
- 完成
Key Steps
1.使用 header 出现在每个页面上的特定标识符准备报告
将 header 和 table header 组放在 Header 部分 中(不在 Tablix 中)
[GroupHeaderText1] 是您要重复的 header 文本,每个组都不同。
它将出现在 Word 文档的每一页上。
3。准备要替换的数据
根据您的报告和数据结构,相应地准备您的数据。
例子
public class SampleData
{
public string GroupHeaderField { get; set; }
public string Data1 { get; set; }
public string Data2 { get; set; }
public string Data3 { get; set; }
}
Part of function for report generation
ReportViewer rv = new ReportViewer();
ReportDataSource reportDataSource = new ReportDataSource();
reportDataSource.Name = "SampleData";
List<SampleData> dataForReport = GetData();
reportDataSource.Value = dataForReport;
rv.LocalReport.DataSources.Add(reportDataSource);
List<string> lstReplace = new List<string>();
//Prepare the data
foreach (SampleData sa in dataForReport)
{
if (!lstReplace.Contains(sa.GroupHeaderField))
{
lstReplace.Add(sa.GroupHeaderField);
}
}
lstReplace 现在包含动态组 headers.
的值
5.准备部分 Header
Get the header we prepared at Step 1 as template, we are using it
for Section Header
WordprocessingDocument wordDoc = WordprocessingDocument.Open(docPath, true);
MainDocumentPart mainDocPart = wordDoc.MainDocumentPart;
HeaderPart defaultHeaderPart = mainDocPart.HeaderParts.FirstOrDefault();
Now we create header part for each section (group)
List<string> newSectionHeaderIds = new List<string>();
foreach (string groupHeaderText in lstReplace)
{
HeaderPart newGroupHeaderPart = mainDocPart.AddNewPart<HeaderPart>();
string sId = mainDocPart.GetIdOfPart(newGroupHeaderPart);
Header newHeader = (Header)defaultHeaderPart.Header.Clone();
foreach (Paragraph p in newHeader.Descendants<Paragraph>())
{
foreach (Run r in p.Descendants<Run>())
{
foreach (Text t in r.Descendants<Text>())
{
t.Text = t.Text.Replace("[GroupHeaderText1]", groupHeaderText);
}
}
}
newHeader.Save(newGroupHeaderPart);
newSectionHeaderIds.Add(sId);
}
这段代码基本上
- 新建一个Header
- 保存 Id 以便稍后用于部分绑定
- 将模板中的内容克隆到此header
- 将标识符替换为组 header 文本
为了更好地理解,您应该使用 Open XML SDK 2.5 for Microsoft Office 并研究 DOCX 文档结构。
6.找到记录组之间的分页符,将其替换为分节符
Section Headers are ready. Now create some sections.
By default, report generated by SSRS has Page Break between groups.
我们只需要更换它们。
创建一个 SectionProperties 模板以在 Word 文档中创建部分,这样我们就可以在组之间有不同的 header。 (您可以使用此 属性 更改 PageSize 等)
SectionProperties defaultProperties = mainDocumentPart.Document.Body.Descendants<SectionProperties>().FirstOrDefault();
defaultProperties.AppendChild(new SectionType { Val = SectionMarkValues.NextPage });
Now find and replace page break
foreach (Paragraph p in document.Body.Descendants<Paragraph>())
{
foreach (Run r in p.Elements<Run>())
{
foreach (Break b in r.Descendants<Break>())
{
if (b.Type != null)
{
if (b.Type.Value == BreakValues.Page)
{
b.Remove(); //Remove the page break
p.Descendants<ParagraphProperties>().FirstOrDefault().AppendChild(defaultProperties.CloneNode(true)); //Replace by a cloned section break
}
}
}
}
}
请注意,页面大小、宽度和高度等属性对于每个部分都是独立的,您应该在步骤 5 中设置它
7.相应地将部分header绑定到每个部分
还记得我们在步骤 5 中创建的 newSectionHeaderIds 列表吗?现在我们绑定它们。
int i = 0;
foreach (SectionProperties sp in document.Body.Descendants<SectionProperties>())
{
//Replace them
sp.RemoveAllChildren<HeaderReference>();
sp.PrependChild(new HeaderReference() { Id = newSectionHeaderIds[i], Type = HeaderFooterValues.Default });
i++;
}
8.完成
最重要的步骤...保存。
wordDoc.Save();
你应该可以开始了,让我知道你有问题。
如MS Documenation所述:
Word does not repeat header rows on page two and greater, although you set the RepeatOnNewPage property of the static header row in a tablix (table, matrix, or list) to True. You can define explicit page breaks in your report to force header rows to appear on new pages. However, because Word applies its own pagination to the rendered report exported to Word, results might vary and the header row might not repeat predictably. The static header row is the row that contains the column headings.
- 在每一页上重复组 Header 仅适用于 PDF 文档
- Word 文档只能在组间重复
那么RDLC报表输出到Word文档时,如何在每一页重复headers组呢?
此解决方案使用 OpenXML 作为文档处理。
谁也可能觉得这有帮助
- 输出带有动态部分的Word文档Header
- 将 SSRS 报告端口打开 XML 文件类型,例如 docm、dotx、dotm...
限制:
- 只支持XML格式的文件(.docx for SSRS),受限于Open XML
- 报告大小 <~= 32MB(文本),受 docx 格式限制
- 报告生成时间成本增加
- 如果同一报告需要提供 .PDF 格式 ,则需要对 header 执行额外的逻辑
- tableheader消耗Header节
- 字段数据导致字段增长时的对齐问题
假设:
- 您已经在 Tablix 中成功准备了分组数据
- 数据组之间的分页已经完成
解法总结:
- 使用特定的标识符准备报告,header出现在每一页
- 在 .DOCX 中呈现报告
- 准备替换数据
- 使用 OpenXML 打开报告
- 准备部分Header
- 找到记录组之间的Page Break并替换为Section Break
- 相应地将部分 header 绑定到每个部分
- 完成
Key Steps
1.使用 header 出现在每个页面上的特定标识符准备报告
将 header 和 table header 组放在 Header 部分 中(不在 Tablix 中)
[GroupHeaderText1] 是您要重复的 header 文本,每个组都不同。
它将出现在 Word 文档的每一页上。
3。准备要替换的数据
根据您的报告和数据结构,相应地准备您的数据。
例子
public class SampleData
{
public string GroupHeaderField { get; set; }
public string Data1 { get; set; }
public string Data2 { get; set; }
public string Data3 { get; set; }
}
Part of function for report generation
ReportViewer rv = new ReportViewer();
ReportDataSource reportDataSource = new ReportDataSource();
reportDataSource.Name = "SampleData";
List<SampleData> dataForReport = GetData();
reportDataSource.Value = dataForReport;
rv.LocalReport.DataSources.Add(reportDataSource);
List<string> lstReplace = new List<string>();
//Prepare the data
foreach (SampleData sa in dataForReport)
{
if (!lstReplace.Contains(sa.GroupHeaderField))
{
lstReplace.Add(sa.GroupHeaderField);
}
}
lstReplace 现在包含动态组 headers.
的值5.准备部分 Header
Get the header we prepared at Step 1 as template, we are using it for Section Header
WordprocessingDocument wordDoc = WordprocessingDocument.Open(docPath, true);
MainDocumentPart mainDocPart = wordDoc.MainDocumentPart;
HeaderPart defaultHeaderPart = mainDocPart.HeaderParts.FirstOrDefault();
Now we create header part for each section (group)
List<string> newSectionHeaderIds = new List<string>();
foreach (string groupHeaderText in lstReplace)
{
HeaderPart newGroupHeaderPart = mainDocPart.AddNewPart<HeaderPart>();
string sId = mainDocPart.GetIdOfPart(newGroupHeaderPart);
Header newHeader = (Header)defaultHeaderPart.Header.Clone();
foreach (Paragraph p in newHeader.Descendants<Paragraph>())
{
foreach (Run r in p.Descendants<Run>())
{
foreach (Text t in r.Descendants<Text>())
{
t.Text = t.Text.Replace("[GroupHeaderText1]", groupHeaderText);
}
}
}
newHeader.Save(newGroupHeaderPart);
newSectionHeaderIds.Add(sId);
}
这段代码基本上
- 新建一个Header
- 保存 Id 以便稍后用于部分绑定
- 将模板中的内容克隆到此header
- 将标识符替换为组 header 文本
为了更好地理解,您应该使用 Open XML SDK 2.5 for Microsoft Office 并研究 DOCX 文档结构。
6.找到记录组之间的分页符,将其替换为分节符
Section Headers are ready. Now create some sections.
By default, report generated by SSRS has Page Break between groups.
我们只需要更换它们。
创建一个 SectionProperties 模板以在 Word 文档中创建部分,这样我们就可以在组之间有不同的 header。 (您可以使用此 属性 更改 PageSize 等)
SectionProperties defaultProperties = mainDocumentPart.Document.Body.Descendants<SectionProperties>().FirstOrDefault();
defaultProperties.AppendChild(new SectionType { Val = SectionMarkValues.NextPage });
Now find and replace page break
foreach (Paragraph p in document.Body.Descendants<Paragraph>())
{
foreach (Run r in p.Elements<Run>())
{
foreach (Break b in r.Descendants<Break>())
{
if (b.Type != null)
{
if (b.Type.Value == BreakValues.Page)
{
b.Remove(); //Remove the page break
p.Descendants<ParagraphProperties>().FirstOrDefault().AppendChild(defaultProperties.CloneNode(true)); //Replace by a cloned section break
}
}
}
}
}
请注意,页面大小、宽度和高度等属性对于每个部分都是独立的,您应该在步骤 5 中设置它
7.相应地将部分header绑定到每个部分
还记得我们在步骤 5 中创建的 newSectionHeaderIds 列表吗?现在我们绑定它们。
int i = 0;
foreach (SectionProperties sp in document.Body.Descendants<SectionProperties>())
{
//Replace them
sp.RemoveAllChildren<HeaderReference>();
sp.PrependChild(new HeaderReference() { Id = newSectionHeaderIds[i], Type = HeaderFooterValues.Default });
i++;
}
8.完成
最重要的步骤...保存。
wordDoc.Save();
你应该可以开始了,让我知道你有问题。