DynamicExamples.cs 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176
  1. using System.Collections.Generic;
  2. using System.Linq;
  3. using NUnit.Framework;
  4. using QuestPDF.Elements;
  5. using QuestPDF.Examples.Engine;
  6. using QuestPDF.Fluent;
  7. using QuestPDF.Helpers;
  8. using QuestPDF.Infrastructure;
  9. namespace QuestPDF.Examples
  10. {
  11. public class OrderItem
  12. {
  13. public string ItemName { get; set; } = Placeholders.Label();
  14. public int Price { get; set; } = Placeholders.Random.Next(1, 11) * 10;
  15. public int Count { get; set; } = Placeholders.Random.Next(1, 11);
  16. }
  17. public struct OrdersTableState
  18. {
  19. public int ShownItemsCount { get; set; }
  20. }
  21. public class OrdersTable : IDynamicComponent<OrdersTableState>
  22. {
  23. private ICollection<OrderItem> Items { get; }
  24. public OrdersTableState State { get; set; }
  25. public OrdersTable(ICollection<OrderItem> items)
  26. {
  27. Items = items;
  28. State = new OrdersTableState
  29. {
  30. ShownItemsCount = 0
  31. };
  32. }
  33. public void Compose(DynamicContext context, IDynamicContainer container)
  34. {
  35. var header = ComposeHeader(context);
  36. var sampleFooter = ComposeFooter(context, Enumerable.Empty<OrderItem>());
  37. var decorationHeight = header.Size.Height + sampleFooter.Size.Height;
  38. var rows = GetItemsForPage(context, decorationHeight).ToList();
  39. var footer = ComposeFooter(context, rows.Select(x => x.Item));
  40. if (State.ShownItemsCount + rows.Count < Items.Count)
  41. container.HasMoreContent();
  42. container.MinimalBox().Decoration(decoration =>
  43. {
  44. decoration.Header().Element(header);
  45. decoration.Content().Box().Stack(stack =>
  46. {
  47. foreach (var row in rows)
  48. stack.Item().Element(row.Element);
  49. });
  50. decoration.Footer().Element(footer);
  51. });
  52. State = new OrdersTableState
  53. {
  54. ShownItemsCount = State.ShownItemsCount + rows.Count
  55. };
  56. }
  57. private IDynamicElement ComposeHeader(DynamicContext context)
  58. {
  59. return context.CreateElement(element =>
  60. {
  61. element
  62. .BorderBottom(1)
  63. .BorderColor(Colors.Grey.Darken2)
  64. .Padding(5)
  65. .Row(row =>
  66. {
  67. var textStyle = TextStyle.Default.SemiBold();
  68. row.ConstantItem(30).Text("#", textStyle);
  69. row.RelativeItem().Text("Item name", textStyle);
  70. row.ConstantItem(50).AlignRight().Text("Count", textStyle);
  71. row.ConstantItem(50).AlignRight().Text("Price", textStyle);
  72. row.ConstantItem(50).AlignRight().Text("Total", textStyle);
  73. });
  74. });
  75. }
  76. private IDynamicElement ComposeFooter(DynamicContext context, IEnumerable<OrderItem> items)
  77. {
  78. var total = items.Sum(x => x.Count * x.Price);
  79. return context.CreateElement(element =>
  80. {
  81. element
  82. .Padding(5)
  83. .AlignRight()
  84. .Text($"Subtotal: {total}$", TextStyle.Default.Size(14).SemiBold());
  85. });
  86. }
  87. private IEnumerable<(OrderItem Item, IDynamicElement Element)> GetItemsForPage(DynamicContext context, float decorationHeight)
  88. {
  89. var totalHeight = decorationHeight;
  90. foreach (var index in Enumerable.Range(State.ShownItemsCount, Items.Count - State.ShownItemsCount))
  91. {
  92. var item = Items.ElementAt(index);
  93. var element = context.CreateElement(content =>
  94. {
  95. content
  96. .BorderBottom(1)
  97. .BorderColor(Colors.Grey.Lighten2)
  98. .Padding(5)
  99. .Row(row =>
  100. {
  101. row.ConstantItem(30).Text(index + 1);
  102. row.RelativeItem().Text(item.ItemName);
  103. row.ConstantItem(50).AlignRight().Text(item.Count);
  104. row.ConstantItem(50).AlignRight().Text($"{item.Price}$");
  105. row.ConstantItem(50).AlignRight().Text($"{item.Count*item.Price}$");
  106. });
  107. });
  108. var elementHeight = element.Size.Height;
  109. if (totalHeight + elementHeight > context.AvailableSize.Height)
  110. break;
  111. totalHeight += elementHeight;
  112. yield return (item, element);
  113. }
  114. }
  115. }
  116. public static class DynamicExamples
  117. {
  118. [Test]
  119. public static void Dynamic()
  120. {
  121. RenderingTest
  122. .Create()
  123. .PageSize(PageSizes.A5)
  124. .ShowResults()
  125. .Render(container =>
  126. {
  127. var items = Enumerable.Range(0, 25).Select(x => new OrderItem()).ToList();
  128. container
  129. .Background(Colors.White)
  130. .Padding(25)
  131. .Decoration(decoration =>
  132. {
  133. decoration
  134. .Header()
  135. .PaddingBottom(5)
  136. .Text(text =>
  137. {
  138. text.DefaultTextStyle(TextStyle.Default.SemiBold().FontColor(Colors.Blue.Darken2).FontSize(16));
  139. text.Span("Page ");
  140. text.CurrentPageNumber();
  141. text.Span(" of ");
  142. text.TotalPages();
  143. });
  144. decoration
  145. .Content()
  146. .Dynamic(new OrdersTable(items));
  147. });
  148. });
  149. }
  150. }
  151. }