Ширина колонок при создании Excel документа с помощью NPOI

Раньше мы работали с какой-то древней библиотекой по работе с Excel-документами — MultiTable. Этот проект изначально написан на Java и был портирован в .Net, и получилось так, что большинство функций скрыто и плохо документировано. Использование предопределенных стилей в этой библиотеке просто ужасное — есть у нас гигантский постоянно дополняемый список стилей, а вот создать свой стиль в процессе генерации документа не представляется возможным. Плюс ко всему библиотека совсем не умеет работать с xlsx. В общем, решили поискать библиотечку для чтения файлов и их генерации посвежее.

Разумеется, наше веб-приложение работает на сервере, на котором не установлен Microsoft Office, поэтому работа с Interop невозможна, к великому сожалению. Для генерации файлов в формате XLSX есть шикарная библиотека EPPLUS — по функциональности сравнима с Interop, умеет практически все. Но единственный ее минус — не работает с XLS. На stackoverflow многие советуют использовать эту библиотечку в связке с ExcelLibrary от гугла, но… посмотрел я эту ExcelLibrary и что-то меня не впечатлило. Документации я не нашел (может плохо искал), а функционал вообще какой-то очень скудный, я даже не нашел как вообще стилизовать документ.

А вот NPOI в этом плане намного лучше. Правда процесс перевода с Interop на NPOI в одном моем проекте занял довольно много времени в силу некоторых отличий со стилями и наборами ячеек.

Например, в NPOI я не нашел как выбрать Range и сразу к нескольким ячейкам применить один стиль. Приходится каждый раз в любой новой ячейке его привязывать явно. Есть, правда DefaultColumnStyle.

Нельзя просто взять и задать значение какой-нибудь ячейке в середине документа. Нужно сначала создать Row, а потом в ней уже создать Cell, а уже только потом вызывать SetCellValue() у созданной ICell. Это не очень удобно.

А еще сюрприз для меня был, когда в сгенерированном документе у меня все мои колонки получились скрытыми. Я долго пытался понять в чем же дело, а потом сообразил, что неправильно использую метод sheet.setColumnWidth(). В него как ширину колонки нужно передавать какое-то странное эфемерное значение UNITS, это как бы обыкновенная ширина, умноженная на 256. Но не всегда… В общем, я не стал глубоко разбираться в этом и просто нашел на просторах интернета этот магический код, который вычисляет необходимую ширину колонки, чтобы она была такая же, как ее делает Interop:

public static int calculateColWidth(double width){ 
                if(width > 254) 
                        return 65280; // максимально возможная ширина 
                if(width > 1){ 
                        int floor = (int)(Math.Floor((width)/5)); 
                        int factor = (30*floor); 
                        int value = 450 + factor + Math.Round((width-1) * 250); 
                        return value; 
                } 
                return 450; // default to column size 1 if zero, one or negative number is passed. 
        }

В нем очень много непонятных мне магических чисел, но это работает! Но с ним тоже есть тонкости — он работает хорошо только со шрифтом Arial. Другие шрифты как-то влияют на ширину колонки и уже не вписываются в заданные рамки, но это уже совсем другая история…

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *