Search code examples
c#npoi

How do Cell Borders in NPOI actually work?


I'm curently creating some Excel sheets in C# with NPOI. When I set different borders for some cells, I encountered some weird behaviour. For example if I want the first cell (0,0) to have a border on the right and the second cell(0,1) a border on the right and the bottom, I write:

XSSFWorkbook wb = new XSSFWorkbook();
ISheet sheet = wb.CreateSheet();

IRow row = sheet.CreateRow(0);
ICell cell = row.CreateCell(0);
ICellStyle styleRight = wb.CreateCellStyle();
styleRight.BorderRight = BorderStyle.Medium;
cell.CellStyle = styleRight;

row = sheet.CreateRow(1);
cell = row.CreateCell(0);
ICellStyle styleBottomRight = wb.CreateCellStyle();
styleBottomRight.BorderRight = BorderStyle.Medium;
styleBottomRight.BorderBottom = BorderStyle.Medium;
cell.CellStyle = styleBottomRight;

this messes up my result and gives my first cell(0,0) a bottom border too.

However if I switch the order of borders for the second cell-style:

row = sheet.CreateRow(1);
cell = row.CreateCell(0);
ICellStyle styleBottomRight = wb.CreateCellStyle();
styleBottomRight.BorderBottom = BorderStyle.Medium;
styleBottomRight.BorderRight = BorderStyle.Medium;
cell.CellStyle = styleBottomRight;

I get my intended result with a singled border on my first cell and two borders on the second cell.

Why does that happen? Why does the order of the two commands change the outcome? Why does the styleBottomRightinfluence how the first cell is styled? I'm using NPOI v2.5.1 in .Net Core 3.1


Solution

  • Looks like a bug at NPOI because for first case generated two borders:

    <borders count="2">
      <border>
        <left/>
        <right/>
        <top/>
        <bottom/>
        <diagonal/>
      </border>
      <border>
         <left/>
         <right style="medium"/>
         <top/>
         <bottom style="medium"/>
         <diagonal/>
      </border>
    

    And both styles refs to last border.

    For second case:

    <borders count="3">
        <border>
            <left/>
            <right/>
            <top/>
            <bottom/>
            <diagonal/>
        </border>
        <border>
            <left/>
            <right style="medium"/>
            <top/>
            <bottom/>
            <diagonal/>
        </border>
        <border>
            <left/>
            <right style="medium"/>
            <top/>
            <bottom style="medium"/>
            <diagonal/>
        </border>
    </borders>
    

    And style refs to the second and third border.

    At any case the order of command will not be important if you explicitly set the values of the borders:

            XSSFWorkbook wb = new XSSFWorkbook();
            ISheet sheet = wb.CreateSheet();
    
            IRow row = sheet.CreateRow(0);
            ICell cell = row.CreateCell(0);
            ICellStyle styleRight = wb.CreateCellStyle();
            styleRight.BorderBottom = BorderStyle.None;
            styleRight.BorderRight = BorderStyle.Medium;
            cell.CellStyle = styleRight;
            
            row = sheet.CreateRow(2);
            cell = row.CreateCell(0);
            ICellStyle styleBottomRight = wb.CreateCellStyle();                        
            styleBottomRight.BorderBottom = BorderStyle.Medium;
            styleBottomRight.BorderRight = BorderStyle.Medium;
            cell.CellStyle = styleBottomRight;