Search code examples
c#itext

iText 7 table with border bottom on last row of each page


I am using iText 7 for creating a table inside the PDF file. My table must have only vertical border (left and right of each column) and in the first row of each page also topo border and in the last row of each page also bottom border.

In each row there's only one columns that can be "rowspanned" on two lines (at max).

I have successfully created the table with repeated header on each page but in the last row of each page i can't draw the bottom border.

Problem can be approached in several ways.

I use a function GetCell to obtain a cell object and then add to table like this

     var stream = new MemoryStream();
     var writer = new PdfWriter(stream);
     var pdf = new PdfDocument(writer);
     pdf.SetDefaultPageSize(PageSize.A4.Rotate());
     var document = new Document(pdf);
     iText.Layout.Element.Table table;

     ...HEADER

     table.AddHeaderCell(GetCell(1, 1, "V", dgv.Columns[i].HeaderText, "{0}", TextAlignment.CENTER, VerticalAlignment.TOP));
     ....AddHeaderCell for all columns

     ....init cycle
   
     table.AddCell(GetCell(1, 1, "F", mystring, TextAlignment.CENTER, VerticalAlignment.TOP).SetBorder(null));
     ...ending cycle
     document.Add(table);
     document.close;
     .....

and then iterate through all cells in table and applied left and right border to cells.

int numrows= table.GetNumberOfRows();
int numcols= table.GetNumberOfColumns();
for (int irow = 0; irow < numrows; irow++)
{
    for (int icol = 0; icol < numcols; icol++)
        {
        try 
            {
            Cell mycell = table.GetCell(irow,icol);
                mycell.SetBorderRight(new SolidBorder(0.5f));
                mycell.SetBorderLeft(new SolidBorder(0.5f));
            }
        catch (NullReferenceException)
            {
            }
        }
}

The biggest difficulty is knowing if the line i'm writing is the last one on the page and another difficult is getting the cell value during the iterative cycle.

Considerations:

I can apply bottom border also in GetCell function in this case i should know in this phase if my row is the last in the page. I've tried with this but the result in not good After cell adding i verify if there's enough space to write another row.

LayoutResult result = table.CreateRendererSubTree().SetParent(document.GetRenderer()).Layout(
    new LayoutContext(new LayoutArea(1, new Rectangle(0, 0, 400, 1e4f))));

LayoutArea currentArea = document.GetRenderer().GetCurrentArea();
Rectangle rectangle = currentArea.GetBBox();
float verticalPosition = rectangle.GetHeight();
float docBottom = rectangle.GetBottom();


float TableHeight = result.GetOccupiedArea().GetBBox().GetHeight();

if (verticalPosition - TableHeight <= docBottom)
{
    // document.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
    //Debug.Print("........................................Last Row splitted");
};


private static Cell GetCell(int cm, int rowspan, string ItsHeader, string mytext, TextAlignment mytextalign,
    VerticalAlignment myvertalign) {
    Cell cell = new Cell(rowspan, cm);
    Paragraph p;
    if (ItsHeader == "V") {
        cell.SetBackgroundColor(iText.Kernel.Colors.ColorConstants.LIGHT_GRAY);
        cell.SetTextAlignment(mytextalign);
        p = new Paragraph(String.Format("{0}", mytext)).SetFontSize(10);
        cell.Add(p);
    } else {
        if (myvertalign == VerticalAlignment.MIDDLE) {
            Div d = new Div();
            d.SetVerticalAlignment(VerticalAlignment.MIDDLE);
            p = new Paragraph(String.Format("{0}", mytext)).SetFontSize(8);
            p.SetTextAlignment(mytextalign);
            d.Add(p);
            cell.Add(d);
        } else {
            cell.SetBackgroundColor(iText.Kernel.Colors.ColorConstants.WHITE);
            p = new Paragraph(String.Format("{0}", mytext)).SetFontSize(8);
            p.SetTextAlignment(mytextalign);
            p.SetMultipliedLeading(1.5f);
            p.SetMarginTop(0);
            cell.Add(p);
        }
    }

    return cell;
}

Thanks for your time and suggestions.

I would obtain something like this Example


Solution

  • Solved in this way. I combined a few things that were giving me problems.

    1. Table With Header Repeated in each page.
    2. Table with borders.
    3. Cell with only Left and Righe Border
    4. Grand Total in last row in last page
    5. For each first row in each page printed 2 Columns Values

    The only condition is to define a variable in which to store the maximum height of the table within the page (horizontal orientation for me). If this height is exceeded, a page break is generated. Thanks for time.

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;
    
    using iText.IO.Image;
    using iText.IO.Font;
    using iText.IO.Font.Constants;
    using iText.Kernel.Events;
    using iText.Kernel.Font;
    using iText.Kernel.Geom;
    using iText.Kernel.Pdf;
    using iText.Kernel.Pdf.Canvas;
    using iText.Kernel.Pdf.Xobject;
    using iText.Layout;
    using iText.Layout.Borders;
    using iText.Layout.Element;
    using iText.Layout.Layout;
    using iText.Layout.Properties;
    using iText.Layout.Renderer;
    using Newtonsoft.Json;
    using System.Collections.Specialized;
    using System.Data;
    using System.Diagnostics;
    using System.IO;
    using System.Web.UI.WebControls;
    using System.Web;
    using iText.IO.Source;
    
    
    namespace PrintPDF7
    {
        public class PrintPDFNew
        {
            public string Stato = "";
            private DataTable TableDati;
            private static string ID = "1472";
            private string Name = "XXXXXXX";
            private static string PathImmagine = "";
            private static Classi.DataJSON varJSON;
            private static Classi.commonParamaters parametersReceveid;
    
        public static string vName
        {   get { return vName; }
            set { vName = value; }
        }
    
        public static string vID
        {
            get { return vID; }
            set { vID = value; }
        }
    
        public byte[]  GetReport(HttpResponse response,  string TipoOutput, string FileToSave, GridView myGrid, Classi.commonParamaters parCommons, string appPath, string ServerMapPath)
            {
                string mystring=null;
                string fCUR = "{0:#,##0.00}";
                int columns_numbers = 18;
    
                PdfDocument pdf;
    
                Memoryms ms=null;
                PdfWriter writer;
                parametersReceveid = parCommons;
    
                PathImmagine = ServerMapPath + @"Images\logo.gif";
    
                TextAlignment vCenter = TextAlignment.CENTER;
                TextAlignment vLeft = TextAlignment.LEFT;
                TextAlignment vRight = TextAlignment.RIGHT;
    
                VerticalAlignment vTop = VerticalAlignment.TOP;
        
                msReader r = new msReader(ServerMapPath + "APP_DATA/DATA_INI.TXT");
                string jsonString = r.ReadToEnd();
                varJSON = JsonConvert.DeserializeObject<Classi.DataJSON>(jsonString);
                r.Close();
    
                parametersReceveid.ID = Convert.ToInt32(((Label)myGrid.Rows[1].Cells[1].Controls[1]).Text);
                ID = ((Label)myGrid.Rows[1].Cells[1].Controls[1]).Text;
                vName = Name;
    
                ms = new MemorymStream();
                writer = new PdfWriter(ms);
                pdf = new PdfDocument(writer);
                pdf.SetDefaultPageSize(PageSize.A4.Rotate());
                var document = new Document(pdf);
                iText.Layout.Element.Table table;
    
                table = MakeTable(columns_numberonne, pdf, document, ID, vName);
                
                TableHeaderEventHandler handler = new TableHeaderEventHandler(table,document, ID, Name);
                pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, handler);
    
                Footer footerHandler = new Footer();
                pdf.AddEventHandler(PdfDocumentEvent.END_PAGE, footerHandler);
    
                // Calculate top margin to be sure that the table will fit the margin.
                float topMargin = 20 + handler.GetTableHeight();
                document.SetMargins(topMargin, 36, 36, 36);
    
                GridView dgv = myGrid;
                int dgvrowcount = dgv.Rows.Count;
                int dgvcolumncount = dgv.Columns.Count;
    
                MakeTableHeader(myGrid, table);
    
                string printID = "V";
                double Total=0; double TotalTax = 0; double TotalTax_Credit = 0;
                Cell TheCell;
                SubtotalHandler handlerTotals = new SubtotalHandler();
                float HeightTable = 0;
                float HeightHeader = 0;
                float HeightTableParz = 0;
    
                HeightHeader = GetHeightTable(table, document);
    
                for (int i = 0; i < dgvrowcount; i++)
                {
                  if (float.Parse(varJSON.Height_MAX_Table) < HeightTable + HeightHeader)
                    {
                    HeightTableParz = HeightTable;
    
                    BordersCells(table, "ROW","F");
                    BordersCells(table, "HEADER","F");
                    BordersCells(table, "FOOTER","F");
                    document.Add(table);
                           
                    document.Add(new AreaBreak(AreaBreakType.NEXT_PAGE));
                    printID = "V";
                    HeightTable = 0;
                    table = null;
                           
                    handlerTotals = new SubtotalHandler();
                    table = MakeTable(columns_numberonne, pdf, document, ID, vName);
                    MakeTableHeader(myGrid, table);
                    }
                    else
                        {
                            printID = (i == 0 ? "V" : "F");
                        }
                    
                    for (int c = 0; c < dgvcolumncount; c++)
                    {
                    switch (dgv.Columns[c].HeaderText)
                    {
                    case "ID":
                        TheCell = GetCell(1, 1, "F", (printID == "V" ? ID : ""), "{0}", vCenter, vTop).SetBorder(null);
                        table.AddCell(TheCell);
                        table.AddCell(GetCell(3, 1, "F", (printID == "V" ? vName : ""), "{0}", vCenter, vTop).SetBorder(null));
                            break;
                    case "Year Pag.":
                    case "Year Rif.":
                    case "Cause":
                            mystring = ((Label)myGrid.Rows[i].Cells[c].Controls[1]).Text;
                            table.AddCell(GetCell(1, 1, "F", mystring, "{0}", vCenter, vTop).SetBorder(null));
                        break;
                    case "Desc":
                        mystring = ((Label)myGrid.Rows[i].Cells[c].Controls[1]).Text;
                        table.AddCell(GetCell(5, 1, "F", mystring, "{0}", vCenter, vTop).SetBorder(null));
                        break;
                    case "Amount":
                        mystring = ((Label)myGrid.Rows[i].Cells[c].Controls[1]).Text.Replace(" €", "");
                        TheCell = GetCell(2, 1, "F", String.Format(fCUR, Convert.ToDouble(mystring)), "{0}", vCenter, vTop).SetBorder(null);
                        TheCell.SetNextRenderer(new SubtotalHandlerAwareCellRenderer(TheCell, handlerTotals, "I", Convert.ToDouble(mystring)));
                        table.AddCell(TheCell);
                        Total += Convert.ToDouble(mystring);
                        break;
                    case "Tax":
                        mystring = ((Label)myGrid.Rows[i].Cells[c].Controls[1]).Text.Replace(" €", "");
                        TheCell = GetCell(2, 1, "F", String.Format(fCUR, Convert.ToDouble(mystring)), "{0}", vCenter, vTop).SetBorder(null);
                        TheCell.SetNextRenderer(new SubtotalHandlerAwareCellRenderer(TheCell, handlerTotals, "O", Convert.ToDouble(mystring)));
                        table.AddCell(TheCell);
                        TotalTax += Convert.ToDouble(mystring);
                        break;
                    case "Tax_Credit":
                        mystring = ((Label)myGrid.Rows[i].Cells[c].Controls[1]).Text.Replace(" €", "");
                        TheCell = GetCell(2, 1, "F", String.Format(fCUR, Convert.ToDouble(mystring)), "{0}", vCenter, vTop).SetBorder(null);
                        TheCell.SetNextRenderer(new SubtotalHandlerAwareCellRenderer(TheCell, handlerTotals, "Tax_Credit", Convert.ToDouble(mystring)));
                        table.AddCell(TheCell);
                        TotalTax_Credit += Convert.ToDouble(mystring);
                        break;
                    default:
                        break;
                        }
                    }
    
                HeightTable = GetHeightTable(table, document) - HeightHeader - HeightTableParz;
                }
                //START WRITING TOTALS
                table.AddCell(GetCell(12, 1, "F", "Total", "{0}", vCenter, vTop).SetBorder(null));
                table.AddCell(GetCell(2, 1, "F", String.Format(fCUR, Total), "{0}", vCenter, vTop).SetBorder(null));
                table.AddCell(GetCell(2, 1, "F", String.Format(fCUR, TotalTax), "{0}", vCenter, vTop).SetBorder(null));
                table.AddCell(GetCell(2, 1, "F", String.Format(fCUR, TotalTax_Credit), "{0}", vCenter, vTop).SetBorder(null));
    
                //END WRITING TOTALS
    
                BordersCells(table, "ROW","V");
                BordersCells(table, "HEADER", "V");
    
                document.Add(table);
    
                footerHandler.WriteTotal(pdf);
    
                document.Close();
    
               byte[] content=null;
               if (TipoOutput == "RESPONSE")
                   {
                        response.ContentType = varJSON.PDF_ContentType;
                        response.AddHeader("content-disposition", "attachment;filename=" + FileToSave);
                        response.Cache.SetCacheability(HttpCacheability.NoCache);
                        response.Outputms.Write(ms.GetBuffer(), 0, ms.GetBuffer().Length);
                   }
               else
                   {
                      content = ms.ToArray();
                   }
    
               return content;
    
    }
    
            private iText.Layout.Element.Table MakeTable(int columns_numbers, PdfDocument pdf, Document doc,string ID, string Name)
            {
                iText.Layout.Element.Table table;
                table = new iText.Layout.Element.Table(UnitValue.CreatePercentArray(columns_numbers));
    
                table.SetWidth(MillimetersToPoints(250));
                table.SetBorder(null);
                table.SetBorderBottom(new SolidBorder(0.5f));
                table.SetBorderTop(new SolidBorder(0.5f));
                table.SetBorderLeft(new SolidBorder(0.5f));
    
                return table;
            }
    
            private void MakeTableHeader(GridView dgv, iText.Layout.Element.Table table)
            
            {
            int dgvrowcount = dgv.Rows.Count;
            int dgvcolumncount = dgv.Columns.Count;
            TextAlignment vCenter = TextAlignment.CENTER;
            VerticalAlignment vTop = VerticalAlignment.TOP;
        
            // Print The DGV Header To Table Header
            for (int i = 0; i < dgvcolumncount; i++)
            {
                switch (dgv.Columns[i].HeaderText)
                {
                    case "ID":
                    case "Year Pag.":
                    case "Year Rif.":
                    case "Cause":
                        table.AddHeaderCell(GetCell(1, 1, "V", dgv.Columns[i].HeaderText, "{0}", vCenter, vTop).SetBorderBottom(new SolidBorder(0.5f)));
                        if (dgv.Columns[i].HeaderText == "ID")
                        {
                            table.AddHeaderCell(GetCell(3, 1, "V", "Name", "{0}", vCenter, vTop).SetBorderBottom(new SolidBorder(0.5f)));
                        }
                        break;
                    case "Desc.":
                        table.AddHeaderCell(GetCell(5, 1, "V", dgv.Columns[i].HeaderText, "{0}", vCenter, vTop).SetBorderBottom(new SolidBorder(0.5f)));
                        break;
                    case "Amount":
                    case "Tax":
                    case "Tax_Credit":
                        table.AddHeaderCell(GetCell(2, 1, "V", dgv.Columns[i].HeaderText, "{0}", vCenter, vTop).SetBorderBottom(new SolidBorder(0.5f)));
                         break;
                    default:
                        break;
                }
            }
    
         }
    
            private float GetHeightTable(iText.Layout.Element.Table TableDati,Document doc)
         {
                IRenderer pRenderer = TableDati.CreateRendererSubTree().SetParent(doc.GetRenderer());
                LayoutResult pLayoutResult = pRenderer.Layout(new LayoutContext(new LayoutArea(0, PageSize.A4)));
                return pLayoutResult.GetOccupiedArea().GetBBox().GetHeight();
    
         }
       
    private void BordersCells(iText.Layout.Element.Table Table, string Tipo, string BordoSuUltima)
            
    {
        int rows_number =0;
        int columns_number = 0;
        bool lastrow = false;
        Cell mycell;
    
        switch (Tipo)
          {  case "HEADER":
                  rows_number = Table.GetHeader().GetNumberOfRows();
                  columns_number = Table.GetHeader().GetNumberOfColumns();
                  break;
              case "ROW":
                   rows_number = Table.GetNumberOfRows();
                   columns_number = Table.GetNumberOfColumns();
                  break;
              case "FOOTER":
                  if (Table.GetFooter() !=null) 
                      {rows_number = Table.GetFooter().GetNumberOfRows();
                          columns_number = Table.GetFooter().GetNumberOfColumns();}
                          break;
              default:
                  rows_number = Table.GetNumberOfRows();
                  columns_number = Table.GetNumberOfColumns();
                  break;
          }
    
        for (int irow = 0; irow < rows_number; irow++)
        {
            for (int icol = 0; icol < columns_number; icol++)
                {
                try 
                    {
                        switch (Tipo)
                        {  case "HEADER":
                                mycell = Table.GetHeader().GetCell(irow, icol);
                                mycell.SetBorderBottom(new SolidBorder(0.5f));
                                break;
                        case "ROW":
                                mycell = Table.GetCell(irow,icol);
                                if (irow + 1 == rows_number)   {  lastrow = true; }
                                if (irow == 0) { mycell.SetBorderTop(new SolidBorder(0.5f)); }
                                break;
                        case "FOOTER":
                                mycell = Table.GetFooter().GetCell(irow, icol);
                                mycell.SetBorderBottom(new SolidBorder(0.5f));
                                break;
                        default:
                                mycell = Table.GetCell(irow, icol);                            
                            break;
                        }
    
                    mycell.SetBorderRight(new SolidBorder(0.5f));
                    mycell.SetBorderLeft(new SolidBorder(0.5f));
    
                    if (mycell.GetColspan() == 12 || (lastrow == true && BordoSuUltima =="V"))
                        {mycell.SetBorderTop(new SolidBorder(0.5f));}
    
                    }
                catch (NullReferenceException)
                    {
                    }
                }
        }
     }
    
            
    private static float MillimetersToPoints(float value)
    {
        return (value / 25.4f) * 72f;
    }
    
    private static Cell GetCell(int cm, int rowspan,string ItsHeader, string MyText, string myformat, TextAlignment AllineaMyText, VerticalAlignment AllineaVert)
    {
        Cell cell = new Cell(rowspan, cm);
        Paragraph p;
        if (ItsHeader == "V")
            {cell.SetBackgroundColor(iText.Kernel.Colors.ColorConstants.LIGHT_GRAY);
             cell.SetTextAlignment(AllineaMyText);
             p = new Paragraph(String.Format(myformat, MyText)).SetFontSize(10);
            cell.SetBorderBottom(new SolidBorder(0.7f));
            cell.Add(p);
        }
        else
            {
             if (AllineaVert == VerticalAlignment.MIDDLE)
                {
                 Div d = new Div();
                 d.SetVerticalAlignment(VerticalAlignment.MIDDLE);
                 p = new Paragraph(String.Format(myformat, MyText)).SetFontSize(8);
                 p.SetTextAlignment(AllineaMyText);
                 d.Add(p);
                 cell.Add(d);
                }
                else {
                cell.SetBackgroundColor(iText.Kernel.Colors.ColorConstants.WHITE);
                p = new Paragraph(String.Format(myformat, MyText)).SetFontSize(8);
                p.SetTextAlignment(AllineaMyText);
                p.SetMultipliedLeading(1.5f);
                p.SetMarginTop(0);
                cell.Add(p);
    }
     }
      return cell;
     
            
            private class TableHeaderEventHandler : IEventHandler
            {
                private iText.Layout.Element.Table table;
                private iText.Layout.Element.Table TableDati;
                private TableRenderer rendererDati;
                private float tableHeight;
                private Document doc;
                private string name;
    
                public TableHeaderEventHandler(iText.Layout.Element.Table tableDati, Document doc, string ID, string Name)
                {
                this.doc = doc;
                this.name = Name;
                this.TableDati = tableDati;
    
                InitTable(ID,Name);
    
                PrintPDFNew.vName = Name;
    
                TableRenderer renderer = (TableRenderer)table.CreateRendererSubTree();
                renderer.SetParent(new DocumentRenderer(doc));
    
                this.rendererDati = (TableRenderer)TableDati.CreateRendererSubTree();
                this.rendererDati.SetParent(new DocumentRenderer(doc));
    
            LayoutResult result = renderer.Layout(new LayoutContext(new LayoutArea(0, PageSize.A4)));
                    tableHeight = result.GetOccupiedArea().GetBBox().GetHeight();
    
                }
    
                public void HandleEvent(Event currentEvent)
                {
                 PdfDocumentEvent docEvent = (PdfDocumentEvent)currentEvent;
                 PdfDocument pdfDoc = docEvent.GetDocument();
                 PdfPage page = docEvent.GetPage();
                 int pageNum = pdfDoc.GetPageNumber(page);
    
                 PdfCanvas canvas = new PdfCanvas(page.NewContentmsBefore(), page.GetResources(), pdfDoc);
                 PageSize pageSize = pdfDoc.GetDefaultPageSize();
                 float coordX = pageSize.GetX() + doc.GetLeftMargin();
                 float coordY = pageSize.GetTop() - doc.GetTopMargin();
                 float width = pageSize.GetWidth() - doc.GetRightMargin() - doc.GetLeftMargin();
                 float height = GetTableHeight();
                 Rectangle rect = new Rectangle(coordX, coordY, width, height);
    
                 IRenderer pRenderer = TableDati.CreateRendererSubTree().SetParent(doc.GetRenderer());
                 LayoutResult pLayoutResult = pRenderer.Layout(new LayoutContext(new LayoutArea(0, PageSize.A4)));
    
                 float y = pLayoutResult.GetOccupiedArea().GetBBox().GetY();
                 float x = pLayoutResult.GetOccupiedArea().GetBBox().GetX();
                 float xBottom = pLayoutResult.GetOccupiedArea().GetBBox().GetBottom();
                 float xHeight = pLayoutResult.GetOccupiedArea().GetBBox().GetHeight();
                 int x2 = pLayoutResult.GetOccupiedArea().GetPageNumber();
    
                 Rectangle pagesize = page.GetPageSizeWithRotation();
                 float HPage = pagesize.GetHeight();
    
                 new Canvas(canvas, rect).Add(table).Close();
                }
    
                public float GetTableHeight()
                {
                    return tableHeight;
                }
    
                private void InitTable(string ID, string Name)
                {
                table = new iText.Layout.Element.Table(UnitValue.CreatePercentArray(new float[] { 33, 33, 33 })).UseAllAvailableWidth();
                table.SetMarginBottom(5);
                table.SetMarginTop(5);
                table.SetBorder(Border.NO_BORDER);
    
                Cell cell = new Cell(1, 1).SetBorder(null);
                ImageData imageData = ImageDataFactory.Create(PrintPDFNew.PathImmagine);
                iText.Layout.Element.Image pdfImg = new iText.Layout.Element.Image(imageData).ScaleAbsolute(Int32.Parse(PrintPDFNew.varJSON.LOGO_LARGHEZZA), Int32.Parse(PrintPDFNew.varJSON.LOGO_Height));
                cell.Add(pdfImg);
                table.AddCell(cell);
    
                cell = new Cell(1, 1).SetBorder(null);
                cell.Add(new Paragraph(PrintPDFNew.varJSON.TITLE).SetFontSize(10).SetTextAlignment(TextAlignment.CENTER));
                table.AddCell(cell);
    
                cell = new Cell(1, 1).SetBorder(null);
                cell.Add(new Paragraph(ID + ' ' + Name).SetFontSize(10).SetTextAlignment(TextAlignment.RIGHT));
                table.AddCell(cell);
    
                cell = new Cell(1, 1).SetBorder(null);
                cell.Add(new Paragraph(PrintPDFNew.varJSON.Office1).SetFontSize(10).SetTextAlignment(TextAlignment.LEFT));
                table.AddCell(cell);
    
                table.AddCell(new Cell(1, 1).SetBorder(null).Add(new Paragraph("")));
    
                cell = new Cell(1, 1).SetBorder(null);
                cell.Add(new Paragraph("Period " + PrintPDFNew.parametersReceveid.Period1 + " " + PrintPDFNew.parametersReceveid.Period2 + " - Competence").SetFontSize(10).SetTextAlignment(TextAlignment.RIGHT));
                table.AddCell(cell);
                }
            }
    
        private class TableFooterEventHandler : IEventHandler
        {
            private iText.Layout.Element.Table table;
            private Document doc;
            private float tableHeight;
    
            public TableFooterEventHandler(iText.Layout.Element.Table table, Document doc, string ID, string Name)
            {
                this.table = table;
                this.doc = doc;
            }
    
            public void HandleEvent(Event currentEvent)
            {
             PdfDocumentEvent docEvent = (PdfDocumentEvent)currentEvent;
             PdfDocument pdfDoc = docEvent.GetDocument();
             PdfPage page = docEvent.GetPage();
    
             int pageNumber = pdfDoc.GetPageNumber(page);
             Rectangle pageSize = page.GetPageSize();
    
             TableRenderer renderer = (TableRenderer)table.CreateRendererSubTree();
             renderer.SetParent(new DocumentRenderer(doc));
    
             // Simulate the positioning of the renderer to find out how much space the header table will occupy.
             LayoutResult result = renderer.Layout(new LayoutContext(new LayoutArea(0, PageSize.A4)));
             tableHeight = result.GetOccupiedArea().GetBBox().GetHeight();
    
            }
        }
    
        protected class Footer : IEventHandler
        {
            protected PdfFormXObject placeholder;
            protected float side = 20;
            protected float x = 800;
            protected float y = 25;
            protected float space = 4.5f;
            protected float descent = 3;
    
            public Footer()
            {
                placeholder = new PdfFormXObject(new Rectangle(0, 0, side, side));
            }
    
            public virtual void HandleEvent(Event @event)
            {
                PdfDocumentEvent docEvent = (PdfDocumentEvent)@event;
                PdfDocument pdf = docEvent.GetDocument();
                PdfPage page = docEvent.GetPage();
                int pageNumber = pdf.GetPageNumber(page);
                Rectangle pageSize = page.GetPageSize();
    
                PdfCanvas pdfCanvas = new PdfCanvas(page);
                Canvas canvas = new Canvas(pdfCanvas, pageSize);
                canvas.SetFontSize(9);
    
                Paragraph p = new Paragraph()
                    .Add("Page ")
                    .Add(pageNumber.ToString())
                    .Add(" di");
    
                canvas.ShowTextAligned(p, x, y, TextAlignment.RIGHT);
                canvas.Close();
    
                pdfCanvas.AddXObjectAt(placeholder, x + space, y - descent);
                pdfCanvas.Release();
            }
    
            public void WriteTotal(PdfDocument pdfDoc)
            {
                Canvas canvas = new Canvas(placeholder, pdfDoc);
                canvas.SetFontSize(9);
                canvas.ShowTextAligned(pdfDoc.GetNumberOfPages().ToString(),
                    0, descent, TextAlignment.LEFT);
                canvas.Close();
            }
        }
    
        private class SubtotalHandler
        {
            private double subtotalSum;
            private double subtotalTax;
            private double subTotalsTax_Credit;
            public virtual void reset(string myField)
            {
              switch (myField)
               {
                 case "I":
                  subtotalSum = 0; break;
                 case "O":
                  subtotalTax = 0; break;
                 case "Tax_Credit":
                   subTotalsTax_Credit = 0;  break;
                 default:
                   break;
                }   
            }
    
            public virtual void add(string myField, double val)
            {
              switch (myField)
              {
               case "I":
               subtotalSum += val; break;
               case "O":
               subtotalTax += val;break;
               case "Tax_Credit":
               subTotalsTax_Credit += val; break;
               default:
               break;
              }   
            }
    
            public double get(string myField)
            {
            switch (myField)
            {
            case "I":
            return subtotalSum;break;
            case "O":
            return subtotalTax;break;
            case "Tax_Credit":
            return subTotalsTax_Credit;break;
            default:
            return 0; break;
                }   
            }
        }
    
            private class SubtotalHandlerAwareCellRenderer : CellRenderer
            {
                private SubtotalHandler subtotalHandler;
                private double myValue;
                private string myField;
                
    
                public SubtotalHandlerAwareCellRenderer(Cell modelElement, SubtotalHandler subtotalHandler, string myField, double myValue)
                    : base(modelElement)
                {
                    this.subtotalHandler = subtotalHandler;
                    this.myValue = myValue;
                    this.myField = myField;
                }
    
                public override void Draw(DrawContext drawContext)
                {
                    base.Draw(drawContext);
                    subtotalHandler.add(myField, myValue);
                }
    
                public override IRenderer GetNextRenderer()
                {
                        return new SubtotalHandlerAwareCellRenderer((Cell)modelElement, subtotalHandler, myField, myValue);
                }
            }
    
            private class SubtotalCellRenderer : CellRenderer
            {
                private SubtotalHandler subtotalHandler;
                private double myValue;
                private string myField;
    
                public SubtotalCellRenderer(Cell modelElement, SubtotalHandler subtotalHandler,string myField)
                    : base(modelElement)
                {
                    this.subtotalHandler = subtotalHandler;
                    this.myField = myField;
                }
    
                public override void Draw(DrawContext drawContext)
                {
                    base.Draw(drawContext);
                    (new Canvas(drawContext.GetCanvas(), drawContext.GetDocument(), occupiedArea.GetBBox())).SetFontSize(8).SetBold().ShowTextAligned(string.Format("{0:#,##0.00}", subtotalHandler.get(myField).ToString()), occupiedArea.GetBBox().GetX() + 38, occupiedArea.GetBBox().GetY() + 3, TextAlignment.CENTER);
                    subtotalHandler.reset(myField);
                }
    
                public override IRenderer GetNextRenderer()
                {
                        return new SubtotalCellRenderer((Cell)modelElement, subtotalHandler,myField);
                }
            }
        }
    }