TableExamples.cs 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589
  1. using System;
  2. using System.Collections.Generic;
  3. using System.ComponentModel;
  4. using System.Diagnostics;
  5. using System.Drawing;
  6. using System.Globalization;
  7. using System.Linq;
  8. using NUnit.Framework;
  9. using QuestPDF.Drawing;
  10. using QuestPDF.Examples.Engine;
  11. using QuestPDF.Fluent;
  12. using QuestPDF.Helpers;
  13. using QuestPDF.Infrastructure;
  14. using Color = QuestPDF.Infrastructure.Color;
  15. using IContainer = QuestPDF.Infrastructure.IContainer;
  16. namespace QuestPDF.Examples
  17. {
  18. public class TableExamples
  19. {
  20. [Test]
  21. public void BasicPlacement()
  22. {
  23. RenderingTest
  24. .Create()
  25. .ProduceImages()
  26. .PageSize(220, 220)
  27. .ShowResults()
  28. .Render(container =>
  29. {
  30. container
  31. .Padding(10)
  32. .MinimalBox()
  33. .Border(1)
  34. .Table(table =>
  35. {
  36. table.ColumnsDefinition(columns =>
  37. {
  38. columns.RelativeColumn();
  39. columns.RelativeColumn();
  40. columns.RelativeColumn();
  41. columns.RelativeColumn();
  42. });
  43. // by using custom 'Element' method, we can reuse visual configuration
  44. table.Cell().Row(1).Column(4).Element(Block).Text("A");
  45. table.Cell().Row(2).Column(2).Element(Block).Text("B");
  46. table.Cell().Row(3).Column(3).Element(Block).Text("C");
  47. table.Cell().Row(4).Column(1).Element(Block).Text("D");
  48. });
  49. });
  50. }
  51. [Test]
  52. public void PagingSupport()
  53. {
  54. RenderingTest
  55. .Create()
  56. .ProducePdf()
  57. .PageSize(420, 220)
  58. .ShowResults()
  59. .Render(container =>
  60. {
  61. container
  62. .Padding(10)
  63. .MinimalBox()
  64. .Border(1)
  65. .Table(table =>
  66. {
  67. table.ColumnsDefinition(columns =>
  68. {
  69. columns.RelativeColumn();
  70. columns.RelativeColumn();
  71. columns.RelativeColumn();
  72. columns.RelativeColumn();
  73. });
  74. // by using custom 'Element' method, we can reuse visual configuration
  75. table.Cell().Element(Block).Text(Placeholders.Label());
  76. table.Cell().Element(Block).Text(Placeholders.Label());
  77. table.Cell().Element(Block).Text(Placeholders.Paragraph());
  78. table.Cell().Element(Block).Text(Placeholders.Label());
  79. });
  80. });
  81. }
  82. [Test]
  83. public void DefaultCellStyle()
  84. {
  85. RenderingTest
  86. .Create()
  87. .ProduceImages()
  88. .PageSize(220, 120)
  89. .ShowResults()
  90. .Render(container =>
  91. {
  92. container
  93. .Padding(10)
  94. .MinimalBox()
  95. .Border(1)
  96. .DefaultTextStyle(TextStyle.Default.Size(16))
  97. .Table(table =>
  98. {
  99. table.ColumnsDefinition(columns =>
  100. {
  101. columns.RelativeColumn();
  102. columns.RelativeColumn();
  103. columns.RelativeColumn();
  104. columns.RelativeColumn();
  105. });
  106. table.Cell().Row(1).Column(1).Element(Block).Text("A");
  107. table.Cell().Row(2).Column(2).Element(Block).Text("B");
  108. table.Cell().Row(1).Column(3).Element(Block).Text("C");
  109. table.Cell().Row(2).Column(4).Element(Block).Text("D");
  110. });
  111. });
  112. }
  113. [Test]
  114. public void ColumnsDefinition()
  115. {
  116. RenderingTest
  117. .Create()
  118. .ProduceImages()
  119. .PageSize(440, 100)
  120. .ShowResults()
  121. .Render(container =>
  122. {
  123. container
  124. .Padding(20)
  125. .Table(table =>
  126. {
  127. table.ColumnsDefinition(columns =>
  128. {
  129. columns.ConstantColumn(50);
  130. columns.ConstantColumn(100);
  131. columns.RelativeColumn(2);
  132. columns.RelativeColumn(3);
  133. });
  134. table.Cell().ColumnSpan(4).LabelCell("Total width: 400px");
  135. table.Cell().ValueCell("50px");
  136. table.Cell().ValueCell("100px");
  137. table.Cell().ValueCell("100px");
  138. table.Cell().ValueCell("150px");
  139. });
  140. });
  141. }
  142. [Test]
  143. public void PartialAutoPlacement()
  144. {
  145. RenderingTest
  146. .Create()
  147. .ProduceImages()
  148. .PageSize(220, 220)
  149. .ShowResults()
  150. .Render(container =>
  151. {
  152. container
  153. .Padding(10)
  154. .MinimalBox()
  155. .Border(1)
  156. .Table(table =>
  157. {
  158. table.ColumnsDefinition(columns =>
  159. {
  160. columns.RelativeColumn();
  161. columns.RelativeColumn();
  162. columns.RelativeColumn();
  163. columns.RelativeColumn();
  164. });
  165. table.Cell().Element(Block).Text("A");
  166. table.Cell().Row(2).Column(2).Element(Block).Text("B");
  167. table.Cell().Element(Block).Text("C");
  168. table.Cell().Row(3).Column(3).Element(Block).Text("D");
  169. table.Cell().ColumnSpan(2).Element(Block).Text("E");
  170. });
  171. });
  172. }
  173. [Test]
  174. public void ExtendLastCellsToTableBottom()
  175. {
  176. RenderingTest
  177. .Create()
  178. .ProduceImages()
  179. .PageSize(220, 170)
  180. .ShowResults()
  181. .Render(container =>
  182. {
  183. container
  184. .Padding(10)
  185. .MinimalBox()
  186. .Border(1)
  187. .Table(table =>
  188. {
  189. table.ColumnsDefinition(columns =>
  190. {
  191. columns.RelativeColumn();
  192. columns.RelativeColumn();
  193. columns.RelativeColumn();
  194. columns.RelativeColumn();
  195. });
  196. table.ExtendLastCellsToTableBottom();
  197. table.Cell().Row(1).Column(1).Element(Block).Text("A");
  198. table.Cell().Row(3).Column(1).Element(Block).Text("B");
  199. table.Cell().Row(2).Column(2).Element(Block).Text("C");
  200. table.Cell().Row(3).Column(3).Element(Block).Text("D");
  201. table.Cell().Row(2).RowSpan(2).Column(4).Element(Block).Text("E");
  202. });
  203. });
  204. }
  205. [Test]
  206. public void Overlapping()
  207. {
  208. RenderingTest
  209. .Create()
  210. .ProduceImages()
  211. .PageSize(170, 170)
  212. .ShowResults()
  213. .Render(container =>
  214. {
  215. container
  216. .Padding(10)
  217. .MinimalBox()
  218. .Border(1)
  219. .Table(table =>
  220. {
  221. table.ColumnsDefinition(columns =>
  222. {
  223. columns.RelativeColumn();
  224. columns.RelativeColumn();
  225. columns.RelativeColumn();
  226. });
  227. table.Cell().Row(1).RowSpan(3).Column(1).ColumnSpan(3).Background(Colors.Grey.Lighten3).MinHeight(150);
  228. table.Cell().Row(1).RowSpan(2).Column(1).ColumnSpan(2).Background(Colors.Grey.Lighten1).MinHeight(100);
  229. table.Cell().Row(3).Column(3).Background(Colors.Grey.Darken1).MinHeight(50);
  230. });
  231. });
  232. }
  233. [Test]
  234. public void Spans()
  235. {
  236. RenderingTest
  237. .Create()
  238. .ProduceImages()
  239. .PageSize(220, 170)
  240. .ShowResults()
  241. .Render(container =>
  242. {
  243. container
  244. .Padding(10)
  245. .Table(table =>
  246. {
  247. table.ColumnsDefinition(columns =>
  248. {
  249. columns.RelativeColumn();
  250. columns.RelativeColumn();
  251. columns.RelativeColumn();
  252. columns.RelativeColumn();
  253. });
  254. table.Cell().RowSpan(2).ColumnSpan(2).Element(Block).Text("1");
  255. table.Cell().ColumnSpan(2).Element(Block).Text("2");
  256. table.Cell().Element(Block).Text("3");
  257. table.Cell().Element(Block).Text("4");
  258. table.Cell().RowSpan(2).Element(Block).Text("5");
  259. table.Cell().ColumnSpan(2).Element(Block).Text("6");
  260. table.Cell().RowSpan(2).Element(Block).Text("7");
  261. table.Cell().Element(Block).Text("8");
  262. table.Cell().Element(Block).Text("9");
  263. });
  264. });
  265. }
  266. [Test]
  267. public void Stability()
  268. {
  269. RenderingTest
  270. .Create()
  271. .ProduceImages()
  272. .PageSize(300, 300)
  273. .ShowResults()
  274. .Render(container =>
  275. {
  276. container
  277. .Padding(10)
  278. .Table(table =>
  279. {
  280. table.ColumnsDefinition(columns =>
  281. {
  282. columns.RelativeColumn();
  283. columns.RelativeColumn();
  284. columns.RelativeColumn();
  285. columns.RelativeColumn();
  286. columns.RelativeColumn();
  287. columns.RelativeColumn();
  288. });
  289. var image = Placeholders.Image(400, 300);
  290. table.Cell().Image(image);
  291. table.Cell().Image(image);
  292. table.Cell().Image(image);
  293. table.Cell().Image(image);
  294. table.Cell().Image(image);
  295. table.Cell().Image(image);
  296. });
  297. });
  298. }
  299. [Test]
  300. public void TableContinued()
  301. {
  302. RenderingTest
  303. .Create()
  304. .ProducePdf()
  305. .PageSize(PageSizes.A5)
  306. .ShowResults()
  307. .Render(container =>
  308. {
  309. var content = new[]
  310. {
  311. ("Label 1", "Value 234"),
  312. ("Label 12", "Value 34"),
  313. ("Label 123", "Value 4")
  314. };
  315. container
  316. .Padding(20)
  317. .AlignRight()
  318. .Column(column =>
  319. {
  320. foreach (var value in content)
  321. {
  322. column.Item().AlignRight().Row(row =>
  323. {
  324. row.AutoItem().Text($"{value.Item1}:").Bold();
  325. row.ConstantItem(75).AlignRight().Text(value.Item2);
  326. });
  327. }
  328. });
  329. });
  330. }
  331. [Test]
  332. public void Bug_RowSpanWorksIncorrectly()
  333. {
  334. // https://github.com/QuestPDF/QuestPDF/issues/552
  335. RenderingTest
  336. .Create()
  337. .ProduceImages()
  338. .PageSize(PageSizes.A5.Landscape())
  339. .ShowResults()
  340. .Render(container =>
  341. {
  342. container.Padding(20).Table(table =>
  343. {
  344. table.ColumnsDefinition(columns =>
  345. {
  346. columns.RelativeColumn(1);
  347. columns.RelativeColumn(2);
  348. columns.RelativeColumn(2);
  349. columns.RelativeColumn(2);
  350. });
  351. foreach (var i in Enumerable.Range(6, 9))
  352. {
  353. table.Cell().Element(CellStyleMainTable).Text($"{i:00}:00");
  354. foreach (var j in Enumerable.Range(1, 3))
  355. table.Cell().Element(CellStyleMainTable).Text("");
  356. }
  357. static IContainer CellStyleMainTable(IContainer container)
  358. {
  359. return container
  360. .Border(0.5f).BorderColor(Colors.Blue.Lighten4)
  361. .Background(Colors.Blue.Lighten5)
  362. .PaddingVertical(5);
  363. }
  364. table.Cell().Row(1).RowSpan(3).Column(2).Element(BlockAccepted).Text("3 rows");
  365. table.Cell().Row(1).RowSpan(6).Column(3).Element(BlockAccepted).Text("6 rows");
  366. table.Cell().Row(3).RowSpan(5).Column(4).Element(BlockAccepted).Text("5 rows");
  367. static IContainer BlockAccepted(IContainer container)
  368. {
  369. return container
  370. .Border(1.5f).BorderColor(Colors.Green.Lighten2)
  371. .Background(Colors.Green.Lighten4);
  372. }
  373. });
  374. });
  375. }
  376. [Test]
  377. public void TableHeader()
  378. {
  379. RenderingTest
  380. .Create()
  381. .ProduceImages()
  382. .PageSize(500, 200)
  383. .ShowResults()
  384. .EnableDebugging()
  385. .Render(container =>
  386. {
  387. var pageSizes = new List<(string name, double width, double height)>()
  388. {
  389. ("Letter (ANSI A)", 8.5f, 11),
  390. ("Legal", 8.5f, 14),
  391. ("Ledger (ANSI B)", 11, 17),
  392. ("Tabloid (ANSI B)", 17, 11),
  393. ("ANSI C", 22, 17),
  394. ("ANSI D", 34, 22),
  395. ("ANSI E", 44, 34)
  396. };
  397. const int inchesToPoints = 72;
  398. container
  399. .Padding(10)
  400. .MinimalBox()
  401. .Border(1)
  402. .Table(table =>
  403. {
  404. IContainer DefaultCellStyle(IContainer container, Color backgroundColor)
  405. {
  406. return container
  407. .Border(1)
  408. .BorderColor(Colors.Grey.Lighten1)
  409. .Background(backgroundColor)
  410. .PaddingVertical(5)
  411. .PaddingHorizontal(10)
  412. .AlignCenter()
  413. .AlignMiddle();
  414. }
  415. table.ColumnsDefinition(columns =>
  416. {
  417. columns.RelativeColumn();
  418. columns.ConstantColumn(75);
  419. columns.ConstantColumn(75);
  420. columns.ConstantColumn(75);
  421. columns.ConstantColumn(75);
  422. });
  423. table.Header(header =>
  424. {
  425. header.Cell().RowSpan(2).Element(CellStyle).ExtendHorizontal().AlignLeft().Text("Document type");
  426. header.Cell().ColumnSpan(2).Element(CellStyle).Text("Inches");
  427. header.Cell().ColumnSpan(2).Element(CellStyle).Text("Points");
  428. header.Cell().Element(CellStyle).Text("Width");
  429. header.Cell().Element(CellStyle).Text("Height");
  430. header.Cell().Element(CellStyle).Text("Width");
  431. header.Cell().Element(CellStyle).Text("Height");
  432. // you can extend already existing styles by creating additional methods
  433. IContainer CellStyle(IContainer container) => DefaultCellStyle(container, Colors.Grey.Lighten3);
  434. });
  435. foreach (var page in pageSizes)
  436. {
  437. table.Cell().Element(CellStyle).ExtendHorizontal().AlignLeft().Text(page.name);
  438. // inches
  439. table.Cell().Element(CellStyle).Text(page.width.ToString(CultureInfo.InvariantCulture));
  440. table.Cell().Element(CellStyle).Text(page.height.ToString(CultureInfo.InvariantCulture));
  441. // points
  442. table.Cell().Element(CellStyle).Text((page.width * inchesToPoints).ToString(CultureInfo.InvariantCulture));
  443. table.Cell().Element(CellStyle).Text((page.height * inchesToPoints).ToString(CultureInfo.InvariantCulture));
  444. IContainer CellStyle(IContainer container) => DefaultCellStyle(container, Colors.White);
  445. }
  446. });
  447. });
  448. }
  449. [Test]
  450. public void PerformanceText_TemperatureReport()
  451. {
  452. RenderingTest
  453. .Create()
  454. .ProducePdf()
  455. .PageSize(PageSizes.A4)
  456. .MaxPages(10_000)
  457. .EnableCaching()
  458. .EnableDebugging(false)
  459. .ShowResults()
  460. .Render(container => GeneratePerformanceStructure(container, 250));
  461. }
  462. public static void GeneratePerformanceStructure(IContainer container, int repeats)
  463. {
  464. container
  465. .Padding(25)
  466. //.Background(Colors.Blue.Lighten2)
  467. .MinimalBox()
  468. .Border(1)
  469. //.Background(Colors.Red.Lighten2)
  470. .Table(table =>
  471. {
  472. table.ColumnsDefinition(columns =>
  473. {
  474. columns.ConstantColumn(100);
  475. columns.RelativeColumn();
  476. columns.ConstantColumn(100);
  477. columns.RelativeColumn();
  478. });
  479. table.ExtendLastCellsToTableBottom();
  480. foreach (var i in Enumerable.Range(0, repeats))
  481. {
  482. table.Cell().RowSpan(3).LabelCell("Project");
  483. table.Cell().RowSpan(3).ShowEntire().ValueCell(Placeholders.Sentence());
  484. table.Cell().LabelCell("Report number");
  485. table.Cell().ValueCell(i.ToString());
  486. table.Cell().LabelCell("Date");
  487. table.Cell().ValueCell(Placeholders.ShortDate());
  488. table.Cell().LabelCell("Inspector");
  489. table.Cell().ValueCell("Marcin Ziąbek");
  490. table.Cell().ColumnSpan(2).LabelCell("Morning weather");
  491. table.Cell().ColumnSpan(2).LabelCell("Evening weather");
  492. table.Cell().ValueCell("Time");
  493. table.Cell().ValueCell("7:13");
  494. table.Cell().ValueCell("Time");
  495. table.Cell().ValueCell("18:25");
  496. table.Cell().ValueCell("Description");
  497. table.Cell().ValueCell("Sunny");
  498. table.Cell().ValueCell("Description");
  499. table.Cell().ValueCell("Windy");
  500. table.Cell().ValueCell("Wind");
  501. table.Cell().ValueCell("Mild");
  502. table.Cell().ValueCell("Wind");
  503. table.Cell().ValueCell("Strong");
  504. table.Cell().ValueCell("Temperature");
  505. table.Cell().ValueCell("17°C");
  506. table.Cell().ValueCell("Temperature");
  507. table.Cell().ValueCell("32°C");
  508. table.Cell().LabelCell("Remarks");
  509. table.Cell().ColumnSpan(3).ValueCell(Placeholders.Paragraph());
  510. }
  511. });
  512. }
  513. // this method uses a higher order function to define a custom and dynamic style
  514. static IContainer Block(IContainer container)
  515. {
  516. return container
  517. .Border(1)
  518. .Background(Colors.Grey.Lighten3)
  519. .ShowOnce()
  520. .MinWidth(50)
  521. .MinHeight(50)
  522. .Padding(10)
  523. .AlignCenter()
  524. .AlignMiddle();
  525. }
  526. }
  527. }