LongTable.cs
C# VB
//// This code is part of Document Solutions for PDF .NET demos.// Copyright (c) MESCIUS inc. All rights reserved.//using System.IO;using System.Drawing;using System.Collections.Generic;using GrapeCity.Documents.Pdf;using GrapeCity.Documents.Text;using GrapeCity.Documents.Layout;using GrapeCity.Documents.Layout.Composition;using GCTEXT = GrapeCity.Documents.Text;using GCDRAW = GrapeCity.Documents.Drawing;
namespace DsPdfWeb.Demos{ // This demo creates a table with variable row height and spanning many pages, // using classes from the GrapeCity.Documents.Layout.Composition namespace. public class LongTable { string[] _headers; TextFormat _thFormat; TextFormat _tdFormat; float _resolution;
readonly List<LayoutRect> _rows = new(); readonly List<LayoutRect> _columns = new(); readonly List<Visual> _cells = new(); readonly List<TextLayout> _texts = new();
GcPdfGraphics _g; View _pageView; Layer _textLayer; LayoutRect _bounds; Surface _sf;
public int CreatePDF(Stream stream) { var doc = new GcPdfDocument();
var page = doc.NewPage(); var pageSize = page.Size; _g = page.Graphics;
_sf = new Surface(); _pageView = _sf.CreateView(pageSize.Width, pageSize.Height); _textLayer = _pageView.CreateSubLayer(); _resolution = _g.Resolution;
var marginsVisual = _pageView.CreateVisual((g, v) => { g.FillRectangle(v.AsRectF(), Color.FromArgb(0xFF, 0xF8, 0xF8)); }); _bounds = marginsVisual.LayoutRect; _bounds.AnchorInflate(null, -_resolution); _sf.PerformLayout();
var noteBounds = AddNote("We create a table with a large number of variable height rows. " + "The table starts at a specified position on the first page, and spans multiple pages.");
var fc = FontCollection.SystemFonts; _thFormat = new TextFormat { Font = fc.FindFamilyName("Trebuchet MS", true) ?? fc.FindFamilyName("Arial", true), FontBold = true, ForeColor = Color.White }; _tdFormat = new TextFormat { Font = fc.FindFamilyName("Trebuchet MS") ?? fc.FindFamilyName("Arial") };
_headers = new string[] { "#", "Lorem", "Ipsum" }; CreateColumns();
var headerRowRect = CreateHeaderRow(); headerRowRect.SetTop(noteBounds, AnchorParam.Bottom, _resolution / 2); FillHeaderRow(headerRowRect);
var prevRowRect = headerRowRect; var numberOfRows = Common.Util.NewRandom().Next(100, 500);
for (int i = 0; i < numberOfRows; i++) { var row = CreateRow((i & 1) != 0); var rc = row.LayoutRect; rc.SetTop(prevRowRect, AnchorParam.Bottom); if (!FillRow(i, rc)) { row.Detach(); CreateTableGrid(); _sf.Render(_g);
_columns.Clear(); _rows.Clear();
page = doc.NewPage(); pageSize = page.Size; _g = page.Graphics;
_sf = new Surface(); _pageView = _sf.CreateView(pageSize.Width, pageSize.Height); _textLayer = _pageView.CreateSubLayer();
marginsVisual = _pageView.CreateVisual((g, v) => { g.FillRectangle(v.AsRectF(), Color.FromArgb(0xFF, 0xF8, 0xF8)); }); _bounds = marginsVisual.LayoutRect; _bounds.AnchorInflate(null, -_resolution); _sf.PerformLayout();
CreateColumns(); headerRowRect = CreateHeaderRow(); headerRowRect.SetTop(_bounds, AnchorParam.Top); FillHeaderRow(headerRowRect);
row = CreateRow((i & 1) != 0); rc = row.LayoutRect; rc.SetTop(headerRowRect, AnchorParam.Bottom);
RestoreRow(rc); } prevRowRect = rc; }
CreateTableGrid(); _sf.Render(_g);
doc.Save(stream); return doc.Pages.Count; }
class TableGridInfo { public TableGridInfo(LayoutRect[] columns, LayoutRect[] rows) { Columns = columns; Rows = rows; } public readonly LayoutRect[] Columns; public readonly LayoutRect[] Rows; }
void CreateTableGrid() { var grid = _pageView.CreateVisual(false); grid.Tag = new TableGridInfo(_columns.ToArray(), _rows.ToArray()); grid.Draw = (g, v) => { var pen = new GCDRAW::Pen(Color.FromArgb(0xDD, 0xDD, 0xDD), 1); var tgi = (TableGridInfo)v.Tag; int lastColumnIndex = tgi.Columns.Length - 1; int lastRowIndex = tgi.Rows.Length - 1;
float xMin = tgi.Columns[0].P0X; float yMin = tgi.Rows[0].P0Y; float xMax = tgi.Columns[lastColumnIndex].P1X; float yMax = tgi.Rows[lastRowIndex].P2Y;
g.DrawRectangle(new RectangleF(xMin, yMin, xMax - xMin, yMax - yMin), pen); for (int i = 0; i < lastColumnIndex; i++) { float x = tgi.Columns[i].P1X; g.DrawLine(new PointF(x, yMin), new PointF(x, yMax), pen); } for (int i = 0; i < lastRowIndex; i++) { float y = tgi.Rows[i].P2Y; g.DrawLine(new PointF(xMin, y), new PointF(xMax, y), pen); } }; }
void CreateColumns() { LayoutRect column1 = _pageView.CreateSpace().LayoutRect; LayoutRect column2 = _pageView.CreateSpace().LayoutRect; LayoutRect column3 = _pageView.CreateSpace().LayoutRect;
column1.AnchorTopBottom(_bounds, 0, 0); column2.AnchorTopBottom(_bounds, 0, 0); column3.AnchorTopBottom(_bounds, 0, 0);
column1.SetLeft(_bounds, AnchorParam.Left); column2.SetLeftAndOpposite(column1, AnchorParam.Right); column3.SetLeftAndOpposite(column2, AnchorParam.Right); column3.SetRight(_bounds, AnchorParam.Right);
column1.SetStarWidth(1); column2.SetStarWidth(3); column3.SetStarWidth(3);
_sf.PerformLayout();
_columns.Add(column1); _columns.Add(column2); _columns.Add(column3); }
LayoutRect CreateHeaderRow() { var rc = _pageView.CreateVisual((g, v) => { g.FillRectangle(v.AsRectF(), Color.FromArgb(0x33, 0x77, 0xFF)); }).LayoutRect; rc.AnchorLeftRight(_bounds, 0, 0); return rc; }
void FillHeaderRow(LayoutRect headerRowRect) { for (int i = 0; i < _columns.Count; i++) { var column = _columns[i]; var tl = new TextLayout(_resolution) { MaxWidth = column.Width, TextAlignment = TextAlignment.Center, MarginLeft = 8, MarginRight = 8, MarginTop = 12 }; tl.Append(_headers[i], _thFormat); tl.PerformLayout();
var cell = _textLayer.CreateVisual(); cell.Tag = tl; cell.Draw = (g, v) => { g.DrawTextLayout((TextLayout)v.Tag, new PointF(0, 0)); }; var rc = cell.LayoutRect; rc.AnchorLeftRight(column, 0, 0); rc.SetTop(headerRowRect, AnchorParam.Top, 0); rc.SetHeight(tl.ContentHeight + 12 + 12); headerRowRect.AppendMinBottom(rc, AnchorParam.Bottom); } _rows.Add(headerRowRect); _sf.PerformLayout(); }
Visual CreateRow(bool even) { var row = _pageView.CreateVisual(); if (even) row.Draw = (g, v) => g.FillRectangle(v.AsRectF(), Color.FromArgb(0xF2, 0xF2, 0xF2)); else row.Draw = (g, v) => g.FillRectangle(v.AsRectF(), Color.White); row.LayoutRect.AnchorLeftRight(_bounds, 0, 0); return row; }
bool FillRow(int index, LayoutRect rowRect) { _cells.Clear(); _texts.Clear(); for (int i = 0; i < _columns.Count; i++) { var column = _columns[i]; var tl = new TextLayout(_resolution) { MaxWidth = column.Width, MarginAll = 8 }; if (i == 0) { tl.TextAlignment = TextAlignment.Center; tl.Append((index + 1).ToString(), _tdFormat); } else { // Add random data: tl.Append(Common.Util.LoremIpsum(1, 1, 2, 1, 15), _tdFormat); } tl.PerformLayout(); _texts.Add(tl);
var cell = _textLayer.CreateVisual(); cell.Tag = tl; cell.Draw = (g, v) => { g.DrawTextLayout((TextLayout)v.Tag, new PointF(0, 0)); }; var rc = cell.LayoutRect; rc.AnchorLeftRight(column, 0, 0); rc.SetTop(rowRect, AnchorParam.Top, 0); rc.SetHeight(tl.ContentHeight + 8 + 8); rowRect.AppendMinBottom(rc, AnchorParam.Bottom); _cells.Add(cell); } _sf.PerformLayout();
if (rowRect.P2Y > _bounds.P2Y) { for (int i = 0; i < _cells.Count; i++) { _cells[i].Detach(); } _cells.Clear(); return false; }
_rows.Add(rowRect); return true; }
void RestoreRow(LayoutRect rowRect) { for (int i = 0; i < _columns.Count; i++) { var tl = _texts[i]; var cell = _textLayer.CreateVisual(); cell.Tag = tl; cell.Draw = (g, v) => { g.DrawTextLayout((TextLayout)v.Tag, new PointF(0, 0)); }; var rc = cell.LayoutRect; rc.AnchorLeftRight(_columns[i], 0, 0); rc.SetTop(rowRect, AnchorParam.Top, 0); rc.SetHeight(tl.ContentHeight + 8 + 8); rowRect.AppendMinBottom(rc, AnchorParam.Bottom); } _sf.PerformLayout(); _rows.Add(rowRect); }
LayoutRect AddNote(string text) { var pad = _resolution / 8f; var tl = new TextLayout(_resolution) { MaxWidth = _bounds.Width, MaxHeight = _bounds.Height, MarginAll = pad }; tl.Append(text, new TextFormat { Font = StandardFonts.Helvetica }); tl.PerformLayout();
var noteVisual = _pageView.CreateVisual(); noteVisual.Tag = tl; noteVisual.Draw = (g, v) => { var rect = v.AsRectF(); g.FillRectangle(rect, Color.FromArgb(213, 221, 240)); g.DrawRectangle(rect, Color.FromArgb(59, 92, 170), 0.5f); g.DrawTextLayout((TextLayout)v.Tag, new PointF(0, 0)); };
var textRect = tl.ContentRectangle; textRect.Inflate(pad, pad); var rc = noteVisual.LayoutRect; rc.AnchorTopLeft(_bounds, 0, 0, textRect.Width, textRect.Height); return rc; } }}