ITextSharp: ручная разбивка таблицы на страницы путем подсчета строк, но что, если строка переносится?

Я использую iTextSharp для создания PDF-файла. Этот PDF-файл содержит таблицу, которую я создаю с помощью DirectContent. Я считаю строки, которые пишу, и делаю document.NewPage(), когда количество строк достигает 45. Кажется, все работает нормально пока не любая из строк переносится во вторую строку. Если это произойдет, мой счетчик строк будет отключен, и в конечном итоге мой разбиение на страницы будет неправильным. Есть ли у кого-нибудь идеи, как я могу обойти эту проблему? Моя полная программа следующая:

using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using iTextSharp.text;
using iTextSharp.text.pdf;
using static iTextSharp.text.Font;

namespace iTextSharp_long_table
{
    class Program
    {
        static void Main(string[] args)
        {
            MemoryStream stream = new MemoryStream();
            using (stream)
            using (Document document = new Document(PageSize.LETTER))
            {
                PdfWriter writer = PdfWriter.GetInstance(document, stream);
                document.Open();

                PdfPTable table = new PdfPTable(4);
                table.TotalWidth = 72 * 7.5f;
                int nrows = 0;
                int topOfPage = 0;

                Font font = new Font(FontFamily.HELVETICA, 9, Font.BOLD);
                Font fontPlain = new Font(FontFamily.HELVETICA, 9);
                for (int i = 0; i < 20 ; i++)    // jobs
                {
                    if (nrows >= 45)
                    {
                        table.WriteSelectedRows(topOfPage, -1, 36, 9 * 72, writer.DirectContent);
                        document.NewPage();
                        topOfPage = table.Size;
                        nrows = 0;
                    }
                    PdfPCell cell2 = new PdfPCell(new Phrase("Job " + (i + 1).ToString(), font));
                    cell2.Border = PdfPCell.TOP_BORDER + PdfPCell.LEFT_BORDER + PdfPCell.BOTTOM_BORDER;
                    cell2.BackgroundColor = new BaseColor(227, 235, 247);
                    cell2.Colspan = 3;
                    table.AddCell(cell2);

                    string currency = string.Format("{0:C}", Math.Round(1.23, 2));
                    cell2 = new PdfPCell(new Phrase(currency, font));
                    cell2.BackgroundColor = new BaseColor(227, 235, 247);
                    cell2.HorizontalAlignment = Element.ALIGN_RIGHT;
                    cell2.Border = PdfPCell.TOP_BORDER + PdfPCell.RIGHT_BORDER + PdfPCell.BOTTOM_BORDER;
                    table.AddCell(cell2);
                    nrows++;

                    // workitems
                    DoWorkItems(ref table, ref nrows, ref topOfPage, document, ref writer, ref fontPlain);

                    // add a blank row before the next job
                    cell2 = new PdfPCell(new Phrase(" "));
                    cell2.Colspan = 4;
                    cell2.Border = PdfPCell.NO_BORDER;
                    table.AddCell(cell2);
                    nrows++;
                }

                table.WriteSelectedRows(topOfPage, -1, 36, 9 * 72, writer.DirectContent);
                document.NewPage();
            }

            byte[] result = stream.GetBuffer();
            File.WriteAllBytes(@"c:\temp\Long Table.pdf", result);
            Process.Start(@"c:\temp\Long Table.pdf");
        }

        public static void DoWorkItems(ref PdfPTable table, ref int nrows, ref int topOfPage, 
            Document document, ref PdfWriter writer, ref Font fontPlain)
        {
            for (int j = 0; j < 5 ; j++)     // workitems
            {
                if (nrows >= 45)
                {
                    table.WriteSelectedRows(topOfPage, -1, 36, 9 * 72, writer.DirectContent);
                    document.NewPage();
                    topOfPage = table.Size;
                    nrows = 0;
                }
                string str = "     - Item " + (j + 1).ToString();
                Phrase phrase = new Phrase(str, fontPlain);
                PdfPCell cell2 = new PdfPCell(phrase);
                cell2.Colspan = 4;
                cell2.Border = PdfPCell.NO_BORDER;
                table.AddCell(cell2);
                nrows++;
            }
        }
    }
}

Есть ли конкретная причина, по которой вы добавляете таблицу, используя прямое содержимое и WriteSelectedRows, вместо того, чтобы добавлять таблицу в документ и позволять itext разделить ее? Эта причина может быть важна для ответа и здесь.

mkl 18.12.2018 08:37

Да (хотя, может быть, мне и не нужно?). Я делаю это, потому что хочу запустить таблицу в определенном месте на странице (в реальной программе я рисую изображение вверху страницы).

Barry Dysert 18.12.2018 09:27

Это не значит, что вы не можете добавить таблицу в документ. Просто установите поля страницы так, чтобы оставшееся пространство было там, где вы хотите разместить таблицу.

mkl 18.12.2018 12:52

Спасибо, @mkl! Вы развеяли мое заблуждение и позволили мне решить эту проблему. Поскольку мне не нужно использовать прямой контент, я могу просто добавить таблицу в документ и позволить iTextSharp выполнить разбиение на страницы. Проблема решена :-).

Barry Dysert 18.12.2018 14:52

Я напишу ответ по этому поводу.

mkl 18.12.2018 16:35
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
1
5
200
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Обычно лучше оставить детали макета в iText, в частности, для основного контента, который может или не может распространяться по страницам. Единственный контент, который обычно требуется для создания макета, - это верхний колонтитул, нижний колонтитул, фон и аналогичные материалы.

В данном случае в комментариях выяснилось, что причина, по которой OP сам обрабатывал детали макета, заключалась в следующем:

I do it because I want to start the table at a specific point on the page (in the real program, I draw an image at the top of the page).

Но это также возможно, если позволить iText обрабатывать макет: нужно просто установить поля страницы так, чтобы оставшееся пространство, пространство, которое iText использует для макета содержимого, было пространством, в котором нужно отображать свой контент.

(Осторожно: вы должны установить поля до, когда создается соответствующая страница. В случае первой страницы это, в частности, означает, что вы должны сделать это перед открытием документа.)

Это решило проблему OP:

Since I don't have to use direct content, I can just add the table to the document and let iTextSharp do the pagination. Problem solved :-).

Другие вопросы по теме