NumberedList.cs
// 完毕:
using System;
using System.IO;
using System.Drawing;
using GrapeCity.Documents.Pdf;
using GrapeCity.Documents.Text;
using GrapeCity.Documents.Drawing;

namespace DsPdfWeb.Demos.Basics
{
    // 演示如何在 GcDocs.Pdf 中将文本段落呈现为编号列表。
    // 本示例中渲染文本页面的方法取自PaginatedText
    // 样本。另请参见TextRendering。
    public class NumberedList
    {
        // 封装示例中使用的页面布局常量:
        private struct Layout
        {
            public static float Margin => 72;
            public static float ListOffset => 24;
        };

        // 在 TextLayout 中的所有段落前面添加数字的实用方法。
        private void AddBullets(GcGraphics g, PointF pt, TextLayout tl, ref int itemNo)
        {
            var tlBullet = g.CreateTextLayout();
            tlBullet.DefaultFormat.Font = StandardFonts.Times;
            tlBullet.DefaultFormat.FontSize = 12;
            foreach (var line in tl.Lines)
            {
                if (line.FirstLineInParagraph)
                {
                    tlBullet.Clear();
                    tlBullet.Append($"{itemNo++})");
                    tlBullet.PerformLayout(true);
                    g.DrawTextLayout(tlBullet, new PointF(pt.X, pt.Y + line.Position + line.LineGap));
                }
            }
        }

        // 主要入口点:
        public int CreatePDF(Stream stream)
        {
            var doc = new GcPdfDocument();
            var ip = new PointF(Layout.Margin, Layout.Margin);
            // 使用 TextLayout.MarginLeft 为列表编号/项目符号保留空间:
            var tl = new TextLayout(72)
            {
                MaxWidth = doc.PageSize.Width - Layout.Margin * 2,
                MaxHeight = doc.PageSize.Height - Layout.Margin * 2,
                ParagraphSpacing = 8,
                MarginLeft = Layout.ListOffset,
            };
            tl.DefaultFormat.Font = StandardFonts.Times;

            // 添加 20 段文本,这些文本将呈现为 20 个项目的编号列表:
            tl.Append(Common.Util.LoremIpsum(20, 1, 6));
            // 执行布局:
            tl.PerformLayout(true);
            // 使用分割选项来提供寡妇/孤儿控制:
            var to = new TextSplitOptions(tl);
            to.MinLinesInFirstParagraph = 2;
            to.MinLinesInLastParagraph = 2;
            // 在循环中,分割并渲染文本(参见PaginatedText),
            // 并添加列表编号:
            int itemNo = 1;
            while (true)
            {
                // 'rest' 将接受不适合的文本:
                var splitResult = tl.Split(to, out TextLayout rest);
                var g = doc.Pages.Add().Graphics;
                g.DrawTextLayout(tl, ip);
                AddBullets(g, ip, tl, ref itemNo);
                if (splitResult != SplitResult.Split)
                    break;
                tl = rest;
            }
            // 完毕:
            doc.Save(stream);
            return doc.Pages.Count;
        }
    }
}