Search code examples
c#.netitext7

How can I disable the splitting of rows (not tables!) in Itext7 for C# when one row is to big to fit on the first page?


How can I disable the splitting of rows in an Itext7-Table if the row is the last one on a page and does not fit to the first page?

The only thing I found is an example for Itext5 where the method setSplitLate() is set to false: http://what-when-how.com/itext-5/dealing-with-large-tables-itext-5/ (Listing 4.19 HeaderFooter2.java)

Does anyone have a solution for this?


Solution

  • In general you should be advised to implement your own custom TableRenderer and handle the layout by your own. However since the TableRenderer's layout algo is indeed very difficult, I advise you to use the next CellRenderer instead:

        class CustomCellRenderer extends CellRenderer {
        public CustomCellRenderer(Cell modelElement) {
            super(modelElement);
        }
    
        @Override
        public LayoutResult layout(LayoutContext layoutContext) {
            LayoutResult result = super.layout(layoutContext);
            if (LayoutResult.FULL != result.getStatus()) {
                result.setStatus(LayoutResult.NOTHING);
                result.setSplitRenderer(null);
                result.setOverflowRenderer(this);
            }
            return result;
        }
    
        @Override
        public IRenderer getNextRenderer() {
            return new CustomCellRenderer((Cell)getModelElement());
        }
    }
    

    As you can see here, if the cell cannot fit on the page, CustomCellRenderer ensures that the layout result will be NOTHING (nothing can be placed on the current area) rather than PARTIAL (the cell can be splitted).

    In your question you've mentioned HeaderFooter2 sample. That is the same sample ported to iText7: https://github.com/itext/i7js-book/blob/develop/src/test/java/com/itextpdf/samples/book/part1/chapter04/Listing_04_19_HeaderFooter2.java

    That's how you could update it using your CustomCellRendrer:

            for (Screening screening : screenings) {
            movie = screening.getMovie();
            cell = new Cell().add(new Paragraph(screening.getLocation()));
            cell.setNextRenderer(new CustomCellRenderer(cell));
            table.addCell(cell);
            cell = new Cell().add(new Paragraph(String.format("%1$tH:%1$tM", screening.getTime())));
            cell.setNextRenderer(new CustomCellRenderer(cell));
            table.addCell(cell);
            cell = new Cell().add(new Paragraph(String.format("%d '", movie.getDuration())));
            cell.setNextRenderer(new CustomCellRenderer(cell));
            table.addCell(cell);
            cell = new Cell().add(new Paragraph(movie.getMovieTitle()));
            cell.setNextRenderer(new CustomCellRenderer(cell));
            table.addCell(cell);
            cell = new Cell().add(new Paragraph(String.valueOf(movie.getYear())));
            cell.setNextRenderer(new CustomCellRenderer(cell));
            table.addCell(cell);
            cell = new Cell();
            cell.setNextRenderer(new CustomCellRenderer(cell));
            cell.add(PojoToElementFactory.getDirectorList(movie));
            table.addCell(cell);
            cell = new Cell();
            cell.setNextRenderer(new CustomCellRenderer(cell));
            cell.add(PojoToElementFactory.getCountryList(movie));
            table.addCell(cell);
        }
    

    As you can see, I set the renderer on the cells via setNextRenderer method. (Note that only "body" cells should be processed with your custom renderer, since we suppose that header and footer will not split).

    Now let's look at the results. That's how split has been processed before: enter image description here

    And that's how it's processed now: enter image description here

    The code I've used in the answer is in Java, but since iText's api is the same in C# as in Java, there should be no problem for you to port it.