NPOI saves the day

Introduction

NPOI is a port of POI for .NET. You know how we in the .NET side like to prefix with N or in the case of JUnit, change J to N for our versions of Java libraries.

NPOI allows us to write Excel files without Excel needing to be installed. By writing files directly it also gives us, speed, less likelihood or us leaving a Excel COM/Automation object in memory and basically a far nicer API.

So how did NPOI save the day?

I am moving an application to WPF and in doing so the third party controls also moved from WinForms to WPF versions. One, a grid control, used to have a great export to Excel feature which output the data in a specific way, unfortunately the WPF version did not write the Excel file in the same format. I was therefore tasked with re-implementing the Excel exporting code. I began with Excel automation which seemed slow and I found it difficult getting the output as we wanted. I then tried a couple of Excel libraries for writing the BIFF format (as used by Excel). Unfortunately these didn’t fully work and/or didn’t do what I needed. Then one of my Java colleagues mentioned POI and checked for an N version of POI, and there it was NPOI. NPOI did everything we needed, thus saving the day.

Let’s see some code

Okay usual prerequisites are

  • Create a project or whichever type you like
  • Using NuGet add the NPOI package

Easy enough.

Logically enough, we have workbooks at the top level with worksheet’s within a workbook. Within the worksheet we have rows and finally cells within the rows, all pretty obvious.

Let’s take a look at some very basic code

var workbook = new XSSFWorkbook();
var worksheet = workbook.CreateSheet("Sheet1");

var row = worksheet.CreateRow(0);
var cell = row.CreateCell(0);

cell.SetCellValue("Hello Excel");

using (var stream = new FileStream("test.xlsx", FileMode.Create, FileAccess.Write))
{
   workbook.Write(stream);
}

Process.Start("test.xlsx");

The above should be pretty self explanatory, after creating the workbook etc. we write the workbook to a file and then using Process, we get Excel to display ht file we’ve created.

Autosizing columns

By default you might feel the columns are too thin, we can therefore iterate over the columns after setting our data and run

for (var c = 0; c < worksheet.GetRow(0).Cells.Count; c++)
{
   worksheet.AutoSizeColumn(c);
}

The above code is simply looping over the columns (I’ve assumed row 0 holds headings for each column – as it were#) and telling the worksheet o auto-size them.

Grouping rows

One thing we have in our data is a need to show parent child relationships in the Excel spreadsheet. Excel allows us to do this by “grouping” rows. For example, if we have

Parent
Child1
Child2

We’d like to show this in Excel in collapsible rows, like a treeview. As such we want the child curves to be within the group so we’d see something like this

+Parent

or expanded

-Parent
Child1
Child2

to achieve this in NPOI (assuming Parent is row 0) we would group row’s 1 and 2, i.e.

worksheet.GroupRow(1, 2);
//if we want to default the rows to collapsed use
worksheet.SetRowGroupCollapsed(1, true);

finally for grouping, the +/- button by default displays at the bottom of the grouping which I always found a little strange, so to have this display at the top of the group we set this via

worksheet.RowSumsBelow = false;

Date format

You may wish to customise the way DateTime’s are displayed, in which case we need to apply a style to the cell object, for example, let’s display the DateTime in the format dd mm yy hh:mm

var creationHelper = workbook.GetCreationHelper();

var cellStyle = workbook.CreateCellStyle();
cellStyle.DataFormat = creationHelper
   .CreateDataFormat()
   .GetFormat("dd mmm yy hh:mm");
cellStyle.Alignment = HorizontalAlignment.Left;

// to apply to our cell we use
cell.CellStyle = cellStyle;

References

https://github.com/tonyqus/npoi