DynamicTable.cs
- //
- // This code is part of Document Solutions for PDF demos.
- // Copyright (c) MESCIUS inc. All rights reserved.
- //
- using System;
- using System.IO;
- using System.Drawing;
- using System.Text;
- using GrapeCity.Documents.Pdf;
- using GrapeCity.Documents.Text;
- using GrapeCity.Documents.Html;
-
- namespace DsPdfWeb.Demos
- {
- // This sample shows how to insert an HTML table with a varying number of rows
- // that might not fit on a single page, into a PDF document starting at an arbitrary
- // position on the page (all data rows must have the same height though).
- // We first create a table with a single data row, measure its height,
- // then create a similar table but with two data rows and measure it too.
- // This allows us to find out the header and data rows' heights, and render
- // the table to a PDF starting at the desired position on the page, and split
- // it into additional pages as needed.
- //
- // Please see notes in comments at the top of HelloWorldHtml
- // sample code for details on adding DsHtml to your projects.
- //
- // See the LongTable demo for a different approach to creating a long
- // dynamic table that does not use DsHtml, and provides better performance.
- public class DynamicTable
- {
- public int CreatePDF(Stream stream)
- {
- // This tag is used to insert the prepared table HTML code
- // into the HTML page template that defines the CSS styles etc.
- // (Using this tag allows you to use string.Format when building
- // the table HTML code, as otherwise curly braces in style
- // definitions would interfere with format specifiers.)
- const string TTAG = "___TABLE___";
-
- // The HTML page template:
- const string tableTpl =
- "<!DOCTYPE html>" +
- "<html>" +
- "<head>" +
- "<style>" +
- "#employees {" +
- " font-family: 'Trebuchet MS', Arial, Helvetica, sans-serif;" +
- " border-collapse: collapse;" +
- " width: 100%;" +
- "}" +
-
- "#employees td, #employees th {" +
- " border: 1px solid #ddd;" +
- " padding: 8px;" +
- "}" +
-
- "#employees tr:nth-child(even){background-color: #f2f2f2;}" +
-
- "#employees tr:hover {background-color: #ddd;}" +
-
- "#employees th {" +
- " padding-top: 12px;" +
- " padding-bottom: 12px;" +
- " text-align: left;" +
- " background-color: #3377ff;" +
- " color: white;" +
- "}" +
- "</style>" +
- "</head>" +
- "<body>" +
-
- TTAG +
-
- "</body>" +
- "</html>";
-
- // The table HTML code format:
- const string tableFmt =
- "<table id='employees'>" +
- " <tr>" +
- " <th>Index</th>" +
- " <th>Lorem</th>" +
- " <th>Ipsum</th>" +
- " </tr>" +
- "{0}" +
- "</table>";
-
- // The table row HTML code format:
- const string dataRowFmt =
- " <tr>" +
- " <td>{0}</td>" +
- " <td>{1}</td>" +
- " <td>{2}</td>" +
- " </tr>";
-
- // Create a new PDF document:
- var doc = new GcPdfDocument();
- // Add a page:
- var page = doc.NewPage();
- // Add a page, get its graphics:
- var g = page.Graphics;
-
- // Set up HTML to PDF formatting options.
- // The most important are the size limits, in this case
- // we do not limit the height as we will adjust it programmatically.
- // Note that in HtmlToPdfFormat, sizes are specified in inches:
- var hf = new HtmlToPdfFormat(false) { MaxPageWidth = page.Size.Width / 72 };
-
- // HTML code for a single data row (with sample data):
- var dataRow = string.Format(dataRowFmt, "a", "b", "c");
- // HTML page with a table that has a single data row:
- var thtml = tableTpl.Replace(TTAG, string.Format(tableFmt, dataRow));
-
- // Create an instance of GcHtmlBrowser that is used to render HTML:
- using var browser = Common.Util.NewHtmlBrowser();
-
- // Measure the HTML for the current GcPdfGraphics:
- var s1 = g.MeasureHtml(browser, thtml, hf);
- // Same HTML page but with two data rows:
- thtml = tableTpl.Replace(TTAG, string.Format(tableFmt, dataRow + dataRow));
- // Measure the new HTML:
- var s2 = g.MeasureHtml(browser, thtml, hf);
- // Calculate data row and header row heights:
- var rowHeight = s2.Height - s1.Height;
- var headerHeight = s1.Height - rowHeight;
-
- // Add a note at the top of the first page:
- var nrc = Common.Util.AddNote(
- "Here we render an HTML table with an unknown number of rows " +
- "that starts at a specified position on the first page, " +
- "and may span multiple pages.",
- page);
-
- // Set up for building the table with random data:
- var lorems = Common.Util.LoremWords();
- var rnd = Common.Util.NewRandom();
- var sb = new StringBuilder();
-
- // Page layout parameters:
- var marginx = nrc.Left;
- var marginy = nrc.Top;
- var x = marginx;
- var y = nrc.Bottom + 36;
- var tbottom = nrc.Bottom + 36 + headerHeight;
- // A random number of data rows to render:
- int nrows = rnd.Next(100, 200);
- // Generate and render the table, adding continuation pages as needed:
- for (int i = 0; i < nrows; ++i)
- {
- sb.AppendFormat(dataRowFmt, i, lorems[rnd.Next(lorems.Count)], lorems[rnd.Next(lorems.Count)]);
- tbottom += rowHeight;
- var lastPage = i == nrows - 1;
- if (tbottom >= page.Size.Height - 72 || lastPage)
- {
- var html = tableTpl.Replace(TTAG, string.Format(tableFmt, sb.ToString()));
- var ok = g.DrawHtml(browser, html, x, y,
- new HtmlToPdfFormat(false) { MaxPageWidth = (page.Size.Width - marginx * 2) / 72 },
- out SizeF size);
- if (!lastPage)
- {
- page = doc.NewPage();
- g = page.Graphics;
- y = 72;
- tbottom = y + headerHeight;
- sb.Clear();
- }
- }
- }
-
- // Done:
- doc.Save(stream);
- return doc.Pages.Count;
- }
- }
- }
-