PDFsharp & MigraDoc Foundation
http://forum.pdfsharp.de/

MergeRight issue - next cell wiped out
http://forum.pdfsharp.de/viewtopic.php?f=2&t=4537
Page 1 of 1

Author:  chris.ball [ Thu Jan 18, 2024 4:59 pm ]
Post subject:  MergeRight issue - next cell wiped out

Hi - this could be a user error or possibly a bug. I've been messing with the MigraDoc/PDFSharp tool for report building and ran into an issue. In certain rows of a table, when I MergeRight 1 for a cell, the cells following the 2 merged cells don't display correctly. THANK YOU for your help!

I've included some code/pseudo code so you can see what's up. & some pics. I'm inside a loop, reading records out of a database & writing data into a table. I've separated the writing out of data into it's own method called "AddDataCell". This method takes the current row, the text to write in the cell, the font, the colSpan (used to set the MergeRight value) and an optional CellAlignment. The main method "WriteReportData" calls the database and we loop thru each record grabbing data & calling AddDataCell for each cell. There are 5 columns in the table. The problem happens when I MergeRight cells 2 + 3. Cell 4 is not written out - or possibly, cell 5 overwriting 4. Any ideas of what may be happening. Can I reset or clear some object in between adding cells? I know this is a lot - here's the code/pseudo code:


protected void AddDataCell(Row row, object content, Font font, int colSpan, CellAlignment justify = CellAlignment.Left) {
if (_defaultCell == null) {
_defaultCell = new Cell();
_defaultCell.Borders.Style = BorderStyle.None;
_defaultCell.Borders.Visible = false;
_defaultCell.MergeRight = 0;
}
string text = content.ToString();
text = text.TrimEnd();
Cell cell = _defaultCell.Clone();
cell.Format.Font = font.Clone();
// IMPORTANT: A cell's MergeRight value is 0 based. A colSpan of 1 would be a .MergeRight of 0
cell.MergeRight = colSpan - 1;
switch (justify) {
case CellAlignment.Center:
cell.Format.Alignment = ParagraphAlignment.Center;
break;
case CellAlignment.Right:
cell.Format.Alignment = ParagraphAlignment.Right;
break;
default: // left justification happens by default
break;
}
cell.AddParagraph(text);
row.Cells.Add(cell.Clone()); // even adding a Clone here didn't help (see note below)
/* Buggy:
* if the mergeRight ever set to something other than a 0, it messes up the next cell that is added in some capacity. It seems to skip over it.
* If I reset it here, it will display the next cell that's added but I loose all columnWidths in the table. I've tried everything. I believe
* this tool may be too buggy to use. Note that re-setting the cell to null doesn't help either. Could something still be in memory?
*/
//cell.MergeRight = 0;
//cell = null;

}

protected override void WriteReportData() {
int rowCount = 0;
Font fontDataRow = _pdfDocument.Styles["DataRow"].Font;
Font fontDataHeader = _pdfDocument.Styles["DataHeader"].Font;
Font fontTotal = _pdfDocument.Styles["GrandTotal"].Font;
Section section = _pdfDocument.Sections[0];

// set up our defaultCell and defaultHeaderCell
Cell defaultHeaderCell = new Cell();
defaultHeaderCell.Style = _pdfDocument.Styles["DataHeader"].Name;
Cell defaultCell = new Cell();
defaultCell.Borders.Style = BorderStyle.None;
defaultCell.Style = StyleNames.Normal;

// Set-up the data table & it's columns
Table table = section.AddTable();
table.Borders.Visible = false;

/* The original iText5 report column width calulation was: table.SetWidths(new float[] { 1.5f, 1.5f, 4.5f, 1.0f, 1.0f });
* CELL_BASE_NUM is calculated by using the 0.5f common denominator of the original table.SetWidths values above. Therefore
* we have: [(3 * 0.5), (3 * 0.5), (5 * 0.5), (2 * 0.5), (2 * 0.5)] which is 19. */

int CELL_BASE_NUM = 19;
float baseColWidth = OrientedPageWidth / CELL_BASE_NUM;
table.Columns.AddColumn();
table.Columns[0].Width = baseColWidth * 4;
table.Columns.AddColumn();
table.Columns[1].Width = baseColWidth * 3;
table.Columns.AddColumn();
table.Columns[2].Width = baseColWidth * 8;
table.Columns.AddColumn();
table.Columns[3].Width = baseColWidth * 2;
table.Columns.AddColumn();
table.Columns[4].Width = baseColWidth * 2;
int cellsPerRow = table.Columns.Count;

// Data Rows
Row row = null;
List<IDbDataParameter> spl = new List<IDbDataParameter>();

foreach (IDataRecord idr in new EnumerableDataReader(_css, GetSQLForReport(), spl)) {
try {

// THE FOLLOWING CONTAINS PSUEDO CODE
if (employee has not been encountered before && is not the first employee) {
// first, write out the last employee's grand total info
row = table.AddRow();
AddDataCell(row, "Hours for " + curEmpName + " for responsibilty " + curResponsibility, fontDataHeader, 3, CellAlignment.Right);
AddDataCell(row, curRoleHours.ToString("0.##"), fontDataHeader, 1, CellAlignment.Right);
AddDataCell(row, curEmpRespCost.ToString("C"), fontDataHeader, 1, CellAlignment.Right);

row = table.AddRow();
AddDataCell(row, "Total hours for " + curEmpName, fontDataHeader, 3, CellAlignment.Right);
AddDataCell(row, curEmpHours.ToString("0.##"), fontDataHeader, 1, CellAlignment.Right);
AddDataCell(row, curEmpCost.ToString("C"), fontDataHeader, 1, CellAlignment.Right);
}

normalRate = read employee info from idr

// reset to current employee's info
curEmployeeID = read employee info from idr
curEmpName = read employee info from idr
curResponsibility = read employee info from idr
curEmpHours = 0;
curEmpCost = 0;
curEmpRespHours = 0;
curEmpRespCost = 0;

// begin writing employee's info on page
row = table.AddRow();
AddDataCell(row, curEmpName, fontDataHeader, 1);
AddDataCell(row, curEmployeeID, fontDataRow, cellsPerRow - 1);
row = table.AddRow();
AddDataCell(row, curResponsibility, fontDataHeader, 1);
AddDataCell(row, "Rate: " + normalRate.ToString("C"), fontDataRow, cellsPerRow - 1);
} else if (curResponsibility != read next employee's responsibility from IDataRecord) {
// first, write out the last employee's info
AddDataCell(row, "Hours for " + curEmpName + " for responsibilty " + curResponsibility, fontDataHeader, 3, CellAlignment.Right);
AddDataCell(row, curEmpRespHours.ToString("0.##"), fontDataHeader, 1, CellAlignment.Right);
AddDataCell(row, curEmpRespCost.ToString("C"), fontDataHeader, 1, CellAlignment.Right);

// reset the current employee's responsibility, hours, costs
curResponsibility = read next employee's responsibility from idr;
curEmpRespHours = 0;
curEmpRespCost = 0;
row = table.AddRow();
AddDataCell(row, curResponsibility, fontDataHeader, 1);
AddDataCell(row, "Normal Rate: " + normalRate, fontDataRow, cellsPerRow - 1);
}


/* Buggy: THIS IS WHERE IT BREAKS
* if the mergeRight ever set to something other than a 0 (shown here as the last argument: colSpan of 1 below), it messes up the next cell that is added in some capacity.
* It seems to skip over it. If I reset it here, it will display the next cell that's added but I loose all columnWidths in the table. I've tried
* everything. I believe this tool may be way too buggy.
*/

// MAIN LINE ITEMS for current Employee

row = table.AddRow();
// method below: AddDataCell(Row row, object content, Font font, int colSpan, optional:CellAlignment justify)
AddDataCell(row, "1", fontDataRow, 1);
//AddDataCell(row, "2", fontDataRow, 1);
//AddDataCell(row, "3", fontDataRow, 1);
AddDataCell(row, "2 + 3", fontDataRow, 2); // doing this breaks it - the MergeRight will cause it not display column 4
AddDataCell(row, "4", fontDataRow, 1);
AddDataCell(row, "5", fontDataRow, 1);
double hours = read next employee's responsibility from idr;
double cost = hours * normalRate;

// keep totals going:
curEmpHours += hours;
curEmpRespHours += hours;
totalHours += hours;
curEmpCost += cost;
curEmpRespCost += cost;
totalCost += cost;
}
catch (Exception e) {
AppStd.LogMessage("Error=" + e.ToString());
}
}

if (rowCount == 0) {
row = table.AddRow();
row = table.AddRow();
row = table.AddRow();
AddDataCell(row, "No data for report", fontDataRow, cellsPerRow);
} else {
// FIRST, write out the last employee's info
row = table.AddRow();
// ...
}
}

Attachments:
File comment: Here is the problem: when columns 2 merges with 3, column 4 doesn't display (or 5 overwrites 4). Why? How do I fix this?
merge.png
merge.png [ 104.59 KiB | Viewed 9088 times ]
File comment: Here is an example when columns 2 & 3 are NOT merged
NoMerge.png
NoMerge.png [ 106.48 KiB | Viewed 9088 times ]

Author:  TH-Soft [ Thu Jan 18, 2024 6:31 pm ]
Post subject:  Re: MergeRight issue - next cell wiped out

Looks like a user error at first glance:
You specify MergeRight = 1 for the "2 + 3" cell, so it gets logically merged with the "4" cell and the contents of the "4" will not show.

Add an empty cell after adding the "2 + 3" cell and everything should be OK.
Or pass a column index into your AddDataCell method so that cells will be filled correctly.

Author:  chris.ball [ Fri Jan 19, 2024 3:27 pm ]
Post subject:  Re: MergeRight issue - next cell wiped out

TH-Soft -- thanks for responding. You wrote: You specify MergeRight = 1 for the "2 + 3" cell, so it gets logically merged with the "4" cell and the contents of the "4" will not show.

But I'm writing into cell 2 with a MergeRight of 1, therefore "skipping" only past cell 3 in that row. That makes the next cell to be written into - albeit implicitly so - #4 in that row - doesn't it?

Thanks for walking me thru this!
cb

ps - I do like your idea of adding the cell index explicitly. that may make my problem go away. I'm going to try that but would still appreciate your reply to my question - cb

Author:  TH-Soft [ Fri Jan 19, 2024 4:14 pm ]
Post subject:  Re: MergeRight issue - next cell wiped out

chris.ball wrote:
That makes the next cell to be written into - albeit implicitly so - #4 in that row - doesn't it?
No, the row still has a cell for each column, even if one cell is ignored.
In your case the MergeRight hides the cell with the text "4".

Each cell has a Column Index. And MergeRight does not change this index.

Page 1 of 1 All times are UTC
Powered by phpBB® Forum Software © phpBB Group
https://www.phpbb.com/