Switch document renderer - Cannot draw elements on already flushed pages - c#

According to this case's answer by Alexey, we can utilize different renderers with customized RootLayoutArea to achieve such layout behavior as below.
Here is the code:
public void ManipulatePdf(String dest)
{
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
Document doc = new Document(pdfDoc, PageSize.A4);
doc.SetMargins(36, 36, 36, 36);
Paragraph p = new Paragraph();
p.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 500; i++)
{
p.Add(new Text(i + " "));
}
doc.Add(p);
RootLayoutArea endOfFullWidthContentArea = (RootLayoutArea)doc.GetRenderer().GetCurrentArea();
ExtendedDocumentRenderer renderer1 = new ExtendedDocumentRenderer(doc,
new RootLayoutArea(endOfFullWidthContentArea.GetPageNumber(), endOfFullWidthContentArea.GetBBox().Clone().SetWidth(200)));
doc.SetRightMargin(doc.GetRightMargin() + doc.GetPageEffectiveArea(PageSize.A4).GetWidth() - 200);
doc.SetRenderer(renderer1);
//The paragraph drawn in the left
Paragraph p1 = new Paragraph();
p1.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 500; i++)
{
p1.Add(new Text(i + " "));
}
doc.Add(p1);
ExtendedDocumentRenderer renderer2 = new ExtendedDocumentRenderer(doc,
new RootLayoutArea(endOfFullWidthContentArea.GetPageNumber(),
endOfFullWidthContentArea.GetBBox().Clone().MoveRight(200 + 20)
.SetWidth(endOfFullWidthContentArea.GetBBox().GetWidth() - 200 - 20)));
doc.SetRightMargin(36);
doc.SetLeftMargin(200 + 36 + 20);
doc.SetRenderer(renderer2);
Paragraph p2 = new Paragraph();
for (int i = 1; i <= 1000; i++)
{
p2.Add(new Text(i + " "));
}
doc.Add(p2);
//Compute which free area is lower in the document
RootLayoutArea areaColumn1 = (RootLayoutArea)renderer1.GetCurrentArea();
RootLayoutArea areaColumn2 = (RootLayoutArea)renderer2.GetCurrentArea();
RootLayoutArea downArea =
areaColumn1.GetPageNumber() > areaColumn2.GetPageNumber() ? areaColumn1 :
(areaColumn1.GetPageNumber() < areaColumn2.GetPageNumber() ? areaColumn2 :
(areaColumn1.GetBBox().GetTop() < areaColumn2.GetBBox().GetTop() ? areaColumn1 : areaColumn2));
doc.SetMargins(36, 36, 36, 36);
DocumentRenderer renderer3 = new ExtendedDocumentRenderer(doc,
new RootLayoutArea(downArea.GetPageNumber(), downArea.GetBBox().Clone().SetX(36).SetWidth(doc.GetPageEffectiveArea(PageSize.A4).GetWidth())));
doc.SetRenderer(renderer3);
Paragraph p3 = new Paragraph();
for (int i = 1; i <= 1000; i++)
{
p3.Add(new Text(i + " "));
}
doc.Add(p3);
doc.Close();
}
private class ExtendedDocumentRenderer : DocumentRenderer
{
public ExtendedDocumentRenderer(Document document, RootLayoutArea currentArea) : base(document)
{
this.currentArea = new RootLayoutArea(currentArea.GetPageNumber(), currentArea.GetBBox().Clone());
this.currentPageNumber = this.currentArea.GetPageNumber();
}
}
We can see that the Paragraph 1 in the left column spans two pages, and the Paragraph 2 spans three pages, under this scenario the code runs well.
But if we add more contents to Paragraph 1 and make it span 3 pages as following:
//The paragraph drawn in the left has more contents
Paragraph p1 = new Paragraph();
p1.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 800; i++)
{
p1.Add(new Text(i + " "));
}
doc.Add(p1);
When the Paragraph 2 is rendering, it throws the exception of "Cannot draw elements on already flushed pages". How to solve this problem? Thank you!

If you elements can span multiple pages then you need to apply immediateFlush=false setting of the DocumentRenderer which goes to its constructor.
You will need to modify your ExtendedDocumentRenderer custom implementation in the following way:
private class ExtendedDocumentRenderer : DocumentRenderer
{
public ExtendedDocumentRenderer(Document document, RootLayoutArea currentArea) : base(document, false)
{
this.currentArea = new RootLayoutArea(currentArea.GetPageNumber(), currentArea.GetBBox().Clone());
this.currentPageNumber = this.currentArea.GetPageNumber();
}
}
And then you will need to call Document#Flush whenever you are done with another document renderer. Essentially in your code sample that call needs to be done after adding each new element. Here is the full code:
Document doc = new Document(pdfDocument, PageSize.A4);
doc.SetMargins(36, 36, 36, 36);
Paragraph p = new Paragraph();
p.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 500; i++)
{
p.Add(new Text(i + " "));
}
doc.Add(p);
RootLayoutArea endOfFullWidthContentArea = (RootLayoutArea)doc.GetRenderer().GetCurrentArea();
ExtendedDocumentRenderer renderer1 = new ExtendedDocumentRenderer(doc,
new RootLayoutArea(endOfFullWidthContentArea.GetPageNumber(), endOfFullWidthContentArea.GetBBox().Clone().SetWidth(200)));
doc.SetRightMargin(doc.GetRightMargin() + doc.GetPageEffectiveArea(PageSize.A4).GetWidth() - 200);
doc.SetRenderer(renderer1);
//The paragraph drawn in the left
Paragraph p1 = new Paragraph();
p1.SetBorder(new SolidBorder(0.5f));
for (int i = 1; i <= 800; i++)
{
p1.Add(new Text(i + " "));
}
doc.Add(p1);
doc.Flush();
ExtendedDocumentRenderer renderer2 = new ExtendedDocumentRenderer(doc,
new RootLayoutArea(endOfFullWidthContentArea.GetPageNumber(),
endOfFullWidthContentArea.GetBBox().Clone().MoveRight(200 + 20)
.SetWidth(endOfFullWidthContentArea.GetBBox().GetWidth() - 200 - 20)));
doc.SetRightMargin(36);
doc.SetLeftMargin(200 + 36 + 20);
doc.SetRenderer(renderer2);
Paragraph p2 = new Paragraph();
for (int i = 1; i <= 1000; i++)
{
p2.Add(new Text(i + " "));
}
doc.Add(p2);
doc.Flush();
//Compute which free area is lower in the document
RootLayoutArea areaColumn1 = (RootLayoutArea)renderer1.GetCurrentArea();
RootLayoutArea areaColumn2 = (RootLayoutArea)renderer2.GetCurrentArea();
RootLayoutArea downArea =
areaColumn1.GetPageNumber() > areaColumn2.GetPageNumber() ? areaColumn1 :
(areaColumn1.GetPageNumber() < areaColumn2.GetPageNumber() ? areaColumn2 :
(areaColumn1.GetBBox().GetTop() < areaColumn2.GetBBox().GetTop() ? areaColumn1 : areaColumn2));
doc.SetMargins(36, 36, 36, 36);
DocumentRenderer renderer3 = new ExtendedDocumentRenderer(doc,
new RootLayoutArea(downArea.GetPageNumber(), downArea.GetBBox().Clone().SetX(36).SetWidth(doc.GetPageEffectiveArea(PageSize.A4).GetWidth())));
doc.SetRenderer(renderer3);
Paragraph p3 = new Paragraph();
for (int i = 1; i <= 1000; i++)
{
p3.Add(new Text(i + " "));
}
doc.Add(p3);
doc.Flush();
doc.Close();

After stepping on the pit before, you can try calling three parameter constructors and setting immediateflush to false.
PdfDocument pdfDoc = new PdfDocument(new PdfWriter(dest));
// setting immediateflush to false
Document doc = new Document(pdfDoc, PageSize.A4, false);

Related

How to set pagewidth (A4) in a flow document

I have created a flow document code-behind. I use a table with four columns.
But the fourth column didn't appear when printing
It seems that the pagewidth is just over half page
When I reduce columnwidth of columns - they appear but the text is wrapping
Here is the code I have
PrintDialog printDlg = new PrintDialog();
FlowDocument FlowTabledoc = new FlowDocument();
// FlowTabledoc.PageWidth = Double.NaN; dit not work
FlowTabledoc.PageWidth = printDlg.PrintableAreaWidth;
Table logflowtable = new Table();
FlowTabledoc.Blocks.Add(logflowtable);
logflowtable.CellSpacing = 5;
int numberOfColumns = 4;
for (int x = 0; x < numberOfColumns; x++)
{
logflowtable.Columns.Add(new TableColumn());
}
logflowtable.Columns[0].Width = new GridLength(60.0, GridUnitType.Pixel);
logflowtable.Columns[1].Width = new GridLength(120.0, GridUnitType.Pixel);
logflowtable.Columns[2].Width = new GridLength(190.0, GridUnitType.Pixel);
logflowtable.Columns[3].Width = new GridLength(90.0, GridUnitType.Pixel);
logflowtable.RowGroups.Add(new TableRowGroup());
int RowAnzahl = LogTB.Rows.Count;
int ColAnzahl = LogTB.Columns.Count;
Paragraph Abschnitt = new Paragraph();
Abschnitt.FontSize = 14;
for (int r = 0; r <= RowAnzahl - 1; r++)
{
logflowtable.RowGroups[0].Rows.Add(new TableRow());
currentRow = logflowtable.RowGroups[0].Rows[r+1];
for (int c = 0; c <= ColAnzahl - 1; c++)
{
currentRow.FontSize = 14;
currentRow.FontWeight = FontWeights.Normal;
currentRow.Cells.Add(new TableCell(new Paragraph(new Run(LogTB.Rows[r][c].ToString()))));
}
FlowTabledoc.Blocks.Add(Abschnitt);
}
FlowTabledoc.Name = "FlowDoc";
IDocumentPaginatorSource idpSource = FlowTabledoc;
printDlg.PrintDocument(idpSource.DocumentPaginator, "Title-Header");
}
}
Solution found:
FlowTabledoc.ColumnWidth = 793;

How to save created PDF file into dynamically file

In my case, I need to let the user shoose the folder and the file name.
I know that I have to make some changes to "PdfWriterGetInstance".
Then how can I change my code to make it as I want:
Document doc = new Document(iTextSharp.text.PageSize.A4, 10, 10, 42, 35);
PdfWriter wri = PdfWriter.GetInstance(doc, new FileStream("Stock.pdf", FileMode.Create));
doc.Open();
Paragraph paragraphe = new Paragraph("Raport of Stock\n\n");
paragraphe.Alignment = Element.ALIGN_CENTER;
doc.Add(paragraphe);
DateTime now = new DateTime();
Paragraph paragraphe3 = new Paragraph(" " + now.ToString()+"\n\n\n");
paragraphe.Alignment = Element.ALIGN_LEFT;
doc.Add(paragraphe3);
PdfPTable table = new PdfPTable(dataGridView1.Columns.Count);
//add the header
for (int j=0; j < dataGridView1.Columns.Count; j++)
{
table.AddCell(new Phrase(dataGridView1.Columns[j].HeaderText));
}
//Flag the first row as a header
table.HeaderRows = 1;
for(int i = 0; i< dataGridView1.Rows.Count; i++)
{
for(int k = 0; k < dataGridView1.Columns.Count; k++)
{
if (dataGridView1[k, i].Value != null)
{
table.AddCell(new Phrase(dataGridView1[k, i].Value.ToString()));
}
}
}
doc.Add(table);
Paragraph paragraphe1 = new Paragraph(" " + "Total items: " +quaq1.ToString());
paragraphe.Alignment = Element.ALIGN_LEFT;
doc.Add(paragraphe1);
Paragraph paragraphe2 = new Paragraph(" " + "Total Price: " + tot1.ToString());
paragraphe.Alignment = Element.ALIGN_LEFT;
doc.Add(paragraphe2);
doc.Close();
Rq: I'm using iTextSharp Assembly.

Repeat Heading to table in pdf

I am using the Itextsharp PDF tool to generate PDF using asp.net and C# , In that in one PDFPtable the last row data is repeating on next page means part of a table forwarded to next page. so want to show header for that Table on next page.
This is my code.
Document doc = new Document(iTextSharp.text.PageSize.A4.Rotate(), 10, 10, 20, 10);
string pdfFilePath = Server.MapPath(".") + "/pdf/myPdf" + Guid.NewGuid().ToString("N") + ".pdf";
try
{
//Create Document class object and set its size to letter and give space left, right, Top, Bottom Margin
FileStream fs = new FileStream(pdfFilePath, FileMode.Create);
//
PdfWriter wri = PdfWriter.GetInstance(doc, fs);
//Header Section
string strImagePath = Server.MapPath("Images");
string strReportName = oReportDTO.strReportName + " " + oReportDTO.oDateRange.FromDate.ToString(DateFormat);
Chunk headerchunk = new Chunk(strReportName, new Font(1, 8.0f));
HeaderFooter oHeader = new HeaderFooter(new Phrase(headerchunk), false);
oHeader.Border = Rectangle.NO_BORDER;
oHeader.Alignment = 1;
doc.Header = oHeader;
//Footer Section
string name ="Logged in as : " +currentLoggedInUser.UserName + new string(' ',70)+ "Page Number : " + doc.PageNumber;
Chunk Footerchunk1 = new Chunk(name, new Font(1, 5.0f));
HeaderFooter oFooter1 = new HeaderFooter(new Phrase(Footerchunk1), true);
oFooter1.Border = Rectangle.NO_BORDER;
oFooter1.Alignment = 1;
doc.Footer = oFooter1;
iTextSharp.text.Image imgFooter = iTextSharp.text.Image.GetInstance(System.Drawing.Image.FromFile(strImagePath + "/TransRisk Logo168x97.png"), System.Drawing.Imaging.ImageFormat.Jpeg);
imgFooter.ScaleAbsolute(80, 50);
Chunk footerchunk = new Chunk(imgFooter, 260.0f, 0.0f);
HeaderFooter oFooter = new HeaderFooter(new Phrase(name),new Phrase(footerchunk));
oFooter.Border =Rectangle.NO_BORDER;
doc.Footer = oFooter;
doc.Open();//Open Document to write
Font font8 = FontFactory.GetFont("ARIAL", 7);
HtmlTable dt = customMatrixReport;
if (dt.Rows.Count > 0)
{
//Craete instance of the pdf table and set the number of column in that table
int startColumnPosition = 1;
int endColumnPosition = 13;//End Column number in Pdf Page
int NoOfReports = Convert.ToInt32(Math.Ceiling((decimal)(dt.Rows[0].Cells.Count - 1) / endColumnPosition));//Count How many Pages to show
int pageRowCount = 0;
List<PdfPCell> lstHeaderCells = new List<PdfPCell>();
PdfPTable oPdfTable = null;
PdfPCell oPdfPCell = null;
for (int report = 1; report <= NoOfReports; ++report)
{
doc.Add(oHeader);
//ColumnText.ShowTextAligned(
int noOfColumns = -1;
if (endColumnPosition > dt.Rows[0].Cells.Count - 1) { endColumnPosition = dt.Rows[0].Cells.Count - 1; noOfColumns = (endColumnPosition - startColumnPosition) + 2; oPdfTable = new PdfPTable(noOfColumns); }
else
{
oPdfTable = new PdfPTable(14);
//Widths Count
noOfColumns = 14;
}
oPdfTable.TotalWidth = 650f;
List<float> lstwidths = new List<float>();
lstwidths.Add(100f);
for (int i = 2; i <= noOfColumns; ++i)
{
lstwidths.Add(80f);
}
oPdfTable.SetTotalWidth(lstwidths.ToArray());
pageRowCount = 0;
for (int rows = 0; rows < dt.Rows.Count; rows++)
{
//PageRowCount
pageRowCount = pageRowCount + 1;
//Description celll
if (rows == 0 )
{
//Background color for table header
oPdfPCell = new PdfPCell(new Phrase(new Chunk(dt.Rows[rows].Cells[0].InnerText, new Font(1, 8.0f, 1, Color.WHITE))));
oPdfPCell.BackgroundColor = new Color(118, 147, 199);
oPdfTable.AddCell(oPdfPCell);
}
else
{
//background color for Table cells
oPdfPCell = new PdfPCell(new Phrase(new Chunk(dt.Rows[rows].Cells[0].InnerText,new Font(1, 8.0f))));
oPdfPCell.BackgroundColor = new Color(232, 237, 255);
oPdfTable.AddCell(oPdfPCell);
}
//for header cel
if (rows == 0)
{
lstHeaderCells.Add(oPdfPCell);
}
for (int column = startColumnPosition; column <= endColumnPosition; column++)
{
if (rows == 0)
{
oPdfPCell = new PdfPCell(new Phrase(new Chunk(dt.Rows[rows].Cells[column].InnerText, new Font(1, 8.0f, 1, Color.WHITE))));
oPdfPCell.BackgroundColor = new Color(118, 147, 199);
oPdfTable.AddCell(oPdfPCell);
}
else
{
oPdfPCell = new PdfPCell(new Phrase(new Chunk(dt.Rows[rows].Cells[column].InnerText, new Font(1, 8.0f))));
oPdfPCell.BackgroundColor = new Color(232, 237, 255);
oPdfPCell.Column.Alignment = 2;
oPdfTable.AddCell(oPdfPCell);
}
if (rows == 0)
{
lstHeaderCells.Add(oPdfPCell);
}
}
if (pageRowCount >= 40 && rows != (dt.Rows.Count - 1))
{
pageRowCount = 0; doc.Add(oPdfTable); doc.NewPage(); doc.Add(oHeader); oPdfTable = new PdfPTable(noOfColumns); oPdfTable.SetTotalWidth(lstwidths.ToArray()); foreach (PdfPCell oHeaderCell in lstHeaderCells) { oPdfTable.AddCell(oHeaderCell); }
}
}
startColumnPosition = endColumnPosition + 1;
endColumnPosition = endColumnPosition + 13;
oPdfTable.SpacingBefore = 10;
oPdfTable.SpacingAfter = 10;
doc.Add(oPdfTable);
//doc.NewPage();
}
}
else
doc.Add(oHeader);
}
finally
{
doc.Close();
}
help me..
Change this line-
if (endColumnPosition > dt.Rows[0].Cells.Count - 1) { endColumnPosition = dt.Rows[0].Cells.Count - 1; noOfColumns = (endColumnPosition - startColumnPosition) + 2; oPdfTable = new PdfPTable(noOfColumns); }
To this-
if (endColumnPosition > dt.Rows[0].Cells.Count - 1) { endColumnPosition = dt.Rows[0].Cells.Count - 1; noOfColumns = (endColumnPosition - startColumnPosition) + 2; oPdfTable = new PdfPTable(noOfColumns); oPdfTable.HeaderRows = 1;}
After this line-
oPdfTable = new PdfPTable(14);
Add this-
oPdfTable.HeaderRows = 1;
Change this line-
pageRowCount = 0; doc.Add(oPdfTable); doc.NewPage(); doc.Add(oHeader); oPdfTable = new PdfPTable(noOfColumns); oPdfTable.SetTotalWidth(lstwidths.ToArray()); foreach (PdfPCell oHeaderCell in lstHeaderCells) { oPdfTable.AddCell(oHeaderCell); }
To this-
pageRowCount = 0; doc.Add(oPdfTable); doc.NewPage(); doc.Add(oHeader); oPdfTable = new PdfPTable(noOfColumns); oPdfTable.HeaderRows = 1; oPdfTable.SetTotalWidth(lstwidths.ToArray()); foreach (PdfPCell oHeaderCell in lstHeaderCells) { oPdfTable.AddCell(oHeaderCell); }

How to parse JSON foreach object in array?

I'm currently looping through a JSON array and generating an object for each item in the array.
I wondering how I can parse data from the current object.
int i = 0, count = 0, yMP, yGP, yGT, favscountB8 = 0;
string gamertag;
JObject o1 = JObject.Parse(File.ReadAllText(#"gamerprofile.json"));
string jsonGamerprofile = JsonConvert.SerializeObject(o1);
var resultObjects = AllChildren(JObject.Parse(jsonGamerprofile))
.First(c => c.Type == JTokenType.Array && c.Path.Contains("favorites"))
.Children<JObject>();
foreach (JObject result in resultObjects)
{
// Here I wish to make the string gamertag = the value of (FavsGTS_gpF) which is inside the current object.
favscountB8 = favscountB8 + 1;
count = count + 1;
yMP = 6 + (62 * (count - 1));
yGP = 7 + (62 * (count - 1));
yGT = 11 + (62 * (count - 1));
Panel mainpanel1 = new Panel();
PictureBox gamerpic1 = new PictureBox();
Label gamertag1 = new Label();
mainpanel1.BackColor = Color.Red;
mainpanel1.Location = new Point(6, yMP);
mainpanel1.Size = new Size(957, 60);
mainpanel1.Name = "mainpanel" + i.ToString();
gamerpic1.BackColor = Color.Azure;
gamerpic1.Location = new Point(7, yGP);
gamerpic1.Size = new Size(54, 54);
gamerpic1.Name = "gamerpic" + i.ToString();
gamerpic1.BringToFront();
gamertag1.ForeColor = Color.FromArgb(110, 120, 127);
gamertag1.BackColor = Color.White;
gamertag1.Text = "Gamertag " + count.ToString();
gamertag1.Font = new Font("Arial Narrow", 14, FontStyle.Bold);
gamertag1.Location = new Point(76, yGT);
gamertag1.Size = new Size(145, 23);
gamertag1.Name = "Gamertag " + count.ToString();
gamertag1.BringToFront();
i = i + 1;
panel4.Controls.Add(gamertag1);
panel4.Controls.Add(gamerpic1);
panel4.Controls.Add(mainpanel1);
}
Inside the foreach statement I wish to make the "gamertag" string equal to the value of "FavsGTS_gpF" which is in each object in the array.

Flow Layout Panel issues when adding group box controls dynamically

I have a list of group box controls and i need to display only few questions in the flow layout panel but it is not displaying properly(width and height reduced) but if I add that controls to the form it is displaying properly
here is my code. please help me how to get back from this problem
code of flow layout panel(displyQues)
private void getQuestions(int quesid)
{
int j = 1;
for (int i = quesid; i <= lstgrpques.Count; i++)
{
displyQues.Location = new Point(15, 30);
displyQues.Show();
displyQues.Size = new System.Drawing.Size(1218, 620);
displyQues.AutoScroll = true;
lstgrpques[i - 1].Show();
displyQues.WrapContents = false;
displyQues.Controls.Add(lstgrpques[i - 1]);
displyQues.FlowDirection = FlowDirection.TopDown;
qstnId++;
j++;
if (j == 5)
{
break;
}
}
}
code of group box
foreach (var question in questions)
{
int QustTxtHght = 0;
GroupBox QuesAnsoptn = new GroupBox();
QuesAnsoptn.Hide();
QuesAnsoptn.AutoSize = true;
QuesAnsoptn.Width = 820;
QuesAnsoptn.Location = new Point(15, QustHgt);
var quest = question.Attribute("ques").Value.Trim();
if (quest.Contains('{'))
{
quest = GetFormatCode(quest);
QustTxtHght = quest.Length +40;
}
else
QustTxtHght = 15;
QuesAnsoptn.Text = question.Attribute("id").Value + ". " + quest;
QuesAnsoptn.Font = new Font("Microsoft Sans Serif", 10);
var options = question.Descendants("option");
var optHgt = 0;
foreach (var option in options)
{
RadioButton rdbtn = new RadioButton();
rdbtn.AutoSize = true;
rdbtn.Location = new Point(20, QustTxtHght + optHgt + 10);
rdbtn.Name = k.ToString();
lstRdOptns.Add(rdbtn);
rdbtn.Font = new Font("Microsoft Sans Serif", 10);
var opt = option.Value;
var loc = 0;
if (opt.Contains('{'))
{
opt = GetFormatCode(opt);
loc = opt.Length + 40;
}
else { loc = rdbtn.Size.Height; }
rdbtn.Text = opt;
optHgt = loc + optHgt;
QuesAnsoptn.Controls.Add(rdbtn);
}
k++;
this.Controls.Add(QuesAnsoptn);
QustHgt = QuesAnsoptn.Size.Height + QustHgt + 20;
QuesAnsoptn.Size = new System.Drawing.Size(820,QuesAnsoptn.Size.Height);
lstgrpques.Add(QuesAnsoptn);
}

Categories

Resources