У меня есть приложение, которое генерирует PDF из HTML, используя evopdf.
в одном сценарии генерация html-таблицы выполняется с помощью c # stringbuilder. и мне нужно включить разрывы страниц в таблицах.
но когда я разбиваю таблицу, используя 'page-break-inside: auto', граница для строки в конце каждой страницы пропадает.
как показать границу после разрыва страницы.
Первоначально я использовал 'border-collapse: collapse' в css, из-за которого граница пропадала в конце страницы. поэтому я изменил его на 'border-collapse: Отдельный' и сгенерировал границы, используя опцию nth-child, чтобы применить единственную границу для ячеек, которая исправляет отсутствующую границу, но создает еще одну проблему слегка смещенных границ, и это выглядит странно в pdf после слияния клетки (клетки с colspan и rowspan)
Я не могу разбить таблицу вручную и включить строки, поскольку у меня нет возможности логически определить, когда разбивать таблицу (или когда страница заполнена).
Я попытался добавить рамку рамки в таблицу, но поскольку таблица охватывает страницы, это мне не помогло.
private string GenerateTable(List<MappingRows> mappingRows,TableMetadata metadata)
{
HtmlTableString.Append("<table class='mapping-table' style='font-size:9px;' width='99%'>");
HtmlTableString.Append("<thead>");
HtmlTableString.Append(GenerateHeaderRow(metadata));
HtmlTableString.Append("</thead>");
HtmlTableString.Append("<tbody>");
HtmlTableString.Append("</table>");
for (int i = startIndex; i <= endIndex; i++)
{
GenerateRow(MappingRows[i],"#fff")
}
}
private string GenerateRow(MappingRow MappingRow,string backColor = "")
{
int maxRowCount = GetMaxRowCountForSection(MappingRow);
for (int i = 0; i < maxRowCount; i++)
{
htmlRowString.Append("<tr>");
// Source
if (MappingRow.SourceMappings != null)
{
int rowSpan = MappingRow.SourceMappings.Count() >= 1 ? 1 : maxRowCount;
if (sourceIndex < MappingRow.SourceMappings.Count())
{
firstSource = MappingRow.SourceMappings[0];
string thisSeries = MappingRow.SourceMappings[sourceIndex].Series != null ? MappingRow.SourceMappings[sourceIndex].Series.SeriesName : "";
if (sourceGroupSeries != thisSeries && !string.IsNullOrWhiteSpace(thisSeries) && !IsComparison)
{
htmlRowString.Append(GenerateCells(MappingRow.SourceMappings[sourceIndex], 1, false, false, true));
}
else
{
htmlRowString.Append(GenerateCells(MappingRow.SourceMappings[sourceIndex], string.IsNullOrWhiteSpace(thisSeries) ? rowSpan : rowSpan - 1)); // subtract 1 from the rowspan if a group series header took 1 of the rows
sourceIndex++;
}
sourceGroupSeries = thisSeries;
}
else if (rowSpan == 1)
{
htmlRowString.Append(GenerateCells(null, rowSpan));
sourceIndex++;
}
}
else
{
if (sourceIndex == 0)
{
htmlRowString.Append(GenerateCells(null, maxRowCount));
sourceIndex = maxRowCount;
}
}
if (i == 0) // first row only
htmlRowString.Append(AddActionCell(MappingRow.Action, maxRowCount));
bool isSplitAction = MappingRow.Action == MappingRowActionType.Split;
// Target A
if (MappingRow.TargetAMappings != null)
{
int rowSpan = MappingRow.TargetAMappings.Count() >= 1 ? 1 : maxRowCount;
if (targetAIndex < MappingRow.TargetAMappings.Count())
{
string thisSeries = MappingRow.TargetAMappings[targetAIndex].Series != null ? MappingRow.TargetAMappings[targetAIndex].Series.SeriesName : "";
if (targetAGroupSeries != thisSeries && !string.IsNullOrWhiteSpace(thisSeries) && !IsComparison)
{
htmlRowString.Append(GenerateCells(MappingRow.TargetAMappings[targetAIndex], 1, true, false, true));
}
else
{
htmlRowString.Append(GenerateCells(MappingRow.TargetAMappings[targetAIndex], string.IsNullOrWhiteSpace(thisSeries) ? rowSpan : rowSpan - 0, true, isSplitAction)); // subtract 1 from the rowspan if a group series header took 1 of the rows
targetAIndex++;
}
targetAGroupSeries = thisSeries;
}
else if (rowSpan == 1)
{
htmlRowString.Append(GenerateCells(null, rowSpan, true));
targetAIndex++;
}
}
else
{
if (targetAIndex == 0)
{
if (MappingRow.Action == MappingRowActionType.Option || MappingRow.Action == MappingRowActionType.Split)
{
htmlRowString.Append(AddCell("", maxRowCount));
targetAIndex = maxRowCount;
int colSpan = IsIncludeActionText || IsIncludeActionIcons ? TotalColumns - 1 : TotalColumns;
for (int x = 0; x < colSpan - 1; x++)
{
if (x == 0)
htmlRowString.Append(AddCell(firstSource.Series == null ? "No recommended was found" : "No recommended series was found", maxRowCount, true));
else
htmlRowString.Append(AddCell("", maxRowCount));
}
}
else
{
htmlRowString.Append(GenerateCells(null, 1, true));
}
}
}
// Target B
if (NumMappingElement > 2)
{
if (MappingRow.TargetBMappings != null)
{
int rowSpan = MappingRow.TargetBMappings.Count() > 1 ? 1 : maxRowCount;
if (targetBIndex < MappingRow.TargetBMappings.Count())
{
string thisSeries = MappingRow.TargetBMappings[targetBIndex].Series != null ? MappingRow.TargetBMappings[targetBIndex].Series.SeriesName : "";
if (targetBGroupSeries != thisSeries && !string.IsNullOrWhiteSpace(thisSeries) && !IsComparison)
{
htmlRowString.Append(GenerateCells(MappingRow.TargetBMappings[targetBIndex], 1, true, false, true));
}
else
{
htmlRowString.Append(GenerateCells(MappingRow.TargetBMappings[targetBIndex], string.IsNullOrWhiteSpace(thisSeries) ? rowSpan : rowSpan - 0, true, isSplitAction)); // subtract 1 from the rowspan if a group series header took 1 of the rows
targetBIndex++;
}
targetBGroupSeries = thisSeries;
}
else if (rowSpan == 1)
{
htmlRowString.Append(GenerateCells(null, rowSpan, true));
targetBIndex++;
}
}
else
{
if (targetBIndex == 0)
{
if (MappingRow.Action == MappingRowActionType.Option || MappingRow.Action == MappingRowActionType.Split)
{
htmlRowString.Append(AddCell("", maxRowCount));
targetBIndex = maxRowCount;
int colSpan = IsIncludeActionText || IsIncludeActionIcons ? TotalColumns - 1 : TotalColumns;
for (int x = 0; x < colSpan - 1; x++)
{
if (x == 0)
htmlRowString.Append(AddCell(firstSource.Series == null ? "No recommended was found" : "No recommended series was found", maxRowCount, true));
else
htmlRowString.Append(AddCell("", maxRowCount));
}
}
else
{
htmlRowString.Append(GenerateCells(null, 1, true));
}
}
}
}
htmlRowString.Append("</tr>");
}
}
private string GenerateCells(Mapping mp, int rowSpan = 1, bool IsTarget = false, bool IsSplitAction = false, bool IsGroupSeries = false)
{
//logic to generate data for each cell in a section of the row based on mapping metadata and add cells(td) with rowspan and colspan
//here i can use inline style or a CSS to apply formatting options
// calls AddCell(string innerHtml, int rowSpan, bool IsName = false, bool isSeriesHeader = false, string backcolor = "")
// which is a plain stringbuilder which forms 'td' with the given inner html and options
}
и CSS здесь
table.mapping-table { padding: 0; border-collapse:separate;page-break-inside:auto !important;
font-family:Arial, Helvetica, sans-serif; font-size:11px;color: #222;}
table.mapping-table tr td .no-border { border:0px solid #fff !important; }
.no-border { border:0px solid #fff !important; }
table.mapping-table tr td .black-border-top { border-top:1px solid !important; }
table.mapping-table .black-border-right { border-right:1px solid ; }
table.mapping-table .black-border-left-top { border-left:1px solid ; border-top:1px solid ; }
table.mapping-table .black-border-right-top { border-right:1px solid; border-top:1px solid; }
table.mapping-table .black-border-top { border-top:1px solid ; }
table.mapping-table .black-border-bottom { border-bottom:1px solid !important; }
table.mapping-table .black-border-left-bottom { border-left:1px solid !important; border-bottom:1px solid !important; }
table.mapping-table .black-border-right-bottom { border-right:1px solid !important; border-bottom:1px solid !important; }
table.mapping-table tr .title-row { font-size:9px !important;}
table.mapping-table .title-row td { border:1px solid white; text-align:center; background-color:#183063; color:White }
table.mapping-table tr .title-row1 { font-size:9px !important;}
table.mapping-table .title-row1 td { text-align:center; background-color:#183063; color:White }
table.mapping-table .sector-category-row td { text-align:left; background-color:#688db1; color:White; font-weight:bold; }
table.mapping-table .asset-class-row td { text-align:left; background-color:#e7f3ff; color:#333; font-weight:bold; padding-left:18px; }
table.mapping-table .white-space { border:0px solid #fff !important;}
table.mapping-table tr {
page-break-inside:avoid !important;
}
table.mapping-table tr td {
border-right:1px solid;
border-bottom:1px solid;
text-align: center;
padding-left: 2px;
padding-right: 2px;
vertical-align: middle;
}
table.mapping-table tr:nth-child(0) td {
border-top:1px solid;
}
table.mapping-table tr td:nth-child(1) {
border-left:1px solid;
}
table.mapping-table .np { padding:0 !important } /* No Padding. Short name for Html output optimization. */
table.nb { width:100% !important; border:0px solid #fff !important; white-space: nowrap;} /* No Border. Short name for Html output optimization. */
table.mapping-table .textAlignLeft { text-align:left; }
table.mapping-table .letterspacing { letter-spacing: .1em; }
см. Скриншот ниже, чтобы посмотреть, как это будет выглядеть. Мне нужно показать границу в конце, выделенную желтым цветом. Я должен использовать только html и css