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 [ 104.59 KiB | Viewed 14910 times ]
|
File comment: Here is an example when columns 2 & 3 are NOT merged
NoMerge.png [ 106.48 KiB | Viewed 14910 times ]
|
|