drvfn
drvfn

Reputation: 13

iTextSharp and datagridview page break

I'm trying to export a datagrid to PDF with iTextSharp and need to make a page break when one column changes. I have this code

using (FileStream stream = new FileStream(savefiledialoge.FileName, FileMode.Create))
{
    try
    {
        pdfdoc = new Document(PageSize.A4, 10f, 10f, 10f, 0f);
        PdfWriter writer = PdfWriter.GetInstance(pdfdoc, stream);
        pdfdoc.SetPageSize(PageSize.A4.Rotate()); // horizontal
        pdfdoc.Open();
        Encabezado();
        for (int i = 0; i <= dataGridView1.RowCount; i++)
        {
            for (int j = 0; j < dataGridView1.Columns.Count; j++)
            {
                if (dataGridView1.Rows[i].Cells["Warehouse"].Value.ToString() == dataGridView1.Rows[i + 1].Cells["Warehouse"].Value.ToString())
                {                                     
                    pdftable.AddCell(new Phrase(dataGridView1.Rows[i].Cells[j].Value.ToString(), text));
                }
                else
                {
                    pdftable.AddCell(new Phrase(dataGridView1.Rows[i].Cells[j].Value.ToString(), text));
                    pdfdoc.Add(pdftable);                                                                                
                    pdfdoc.NewPage();
                    pdftable.DeleteBodyRows();                                        
                }                                    
            }
        }
    }
    catch (Exception ex)
    {
        MessageBox.Show(ex.Message, "error occured ", MessageBoxButtons.OK, MessageBoxIcon.Error);
    }
}

but I have two problems, one of the rows is added in a new page

enter image description here

and the compilation gives me an error:

"Index was out of range, must be nonnegative and less than the size of the collection."

Upvotes: 1

Views: 516

Answers (1)

mkl
mkl

Reputation: 95918

You have the case differentiation inside your loop over the columns:

for (int j = 0; j < dataGridView1.Columns.Count; j++)
{
    if (dataGridView1.Rows[i].Cells["Warehouse"].Value.ToString() == dataGridView1.Rows[i + 1].Cells["Warehouse"].Value.ToString())
    {
        pdftable.AddCell(new Phrase(dataGridView1.Rows[i].Cells[j].Value.ToString(), text));
    }
    else
    {
        pdftable.AddCell(new Phrase(dataGridView1.Rows[i].Cells[j].Value.ToString(), text));
        pdfdoc.Add(pdftable);
        pdfdoc.NewPage();
        pdftable.DeleteBodyRows();
    }
}

The effect: Let's assume i currently is the value for the last row for a given warehouse. Thus, inside the j loop above you'll go into the else branch all the time, so

  • For j == 0 your code already adds the table with the still incomplete row i ("incomplete" as only the cell for the first column has been added) to the document. iText does not draw the incomplete row i but goes to the next page with that single column still in the table object.
  • For the next values of j before the final column, the row still is incomplete, so pdfdoc.Add(pdftable) adds nothing to the page but stores the new cells in the table object. pdfdoc.NewPage() does not create yet another page as the current page still is empty.
  • For the last value of j the row i finally is complete, so pdfdoc.Add(pdftable) adds a single-row table and pdfdoc.NewPage() creates yet another new page.

You should instead first add the complete current row i to the table in the body of your loop over i and only thereafter test whether a change of warehouse will occur in the next row; i.e. replace the quoted code above by

for (int j = 0; j < dataGridView1.Columns.Count; j++)
{
    pdftable.AddCell(new Phrase(dataGridView1.Rows[i].Cells[j].Value.ToString(), text));
}

if (i == dataGridView1.RowCount - 1)
{
    pdfdoc.Add(pdftable);
}
else if (dataGridView1.Rows[i].Cells["Warehouse"].Value.ToString() != dataGridView1.Rows[i + 1].Cells["Warehouse"].Value.ToString())
{
    pdfdoc.Add(pdftable);
    pdfdoc.NewPage();
    pdftable.DeleteBodyRows();
}

Concerning the "Index out of range":

  • On one hand don't compare the warehouse with the value in the next row if you are in the last row already, see above.
  • On the other hand, as @Bruno already mentioned, the loop over i should stop earlier, instead of

    for (int i = 0; i <= dataGridView1.RowCount; i++) 
    

    use

    for (int i = 0; i < dataGridView1.RowCount; i++)
    

Upvotes: 1

Related Questions