1

How to add new rows with cell data and styles in Excel using OpenXML and C#

1 Answer 1

2

Though it was a question from my side but not anymore. I'll mention my R&D and code stuff to which resolved my problem.

public override void AddExcelRows(string[] bufData, int cReport, int cSection, int nrow, bool insertRow)
{
    int rowIndex;
    int colIndex;

    rowIndex = //some number
    colIndex = //some number

    Sheet sheet = wbPart.Workbook.Descendants<Sheet>().Where((s) => s.Name == currentSheetName).FirstOrDefault();

    WorksheetPart worksheetPart = wbPart.GetPartById(sheet.Id) as WorksheetPart;
    SharedStringTablePart shareStringPart = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
    SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();

    for (int colOffset = 0; colOffset <= some number; colOffset++)
    {
        if (bufData[colOffset] != null)
        {
            int index = InsertSharedStringItem(bufData[colOffset], shareStringPart);

            var columnName = GetExcelColumnName(colIndex + colOffset);

            Cell cell = InsertCellInWorksheet(columnName, rowIndex, worksheetPart);
            if (cell.CellValue !=null && cell.CellValue.InnerText == bufData[colOffset])//if same value is already present in current cell then skip writign again. it was causing issue writng [kW] for project Technical report.
            {
                continue; 
            }
            cell.CellValue = new CellValue(index.ToString());
            cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
        }
    }
    if (insertRow)
    {
        uint nextRowIndex = (uint)rowIndex + 1; //Add min 3 rows in excel with styles (border line)
        Row oldRow = sheetData.Elements<Row>().Where(r => r.RowIndex == nextRowIndex).First();
        var newRow = oldRow.CopyToLine((uint)nextRowIndex, sheetData);
    }
    wbPart.Workbook.Save();
}   

Helper methods:

private string GetExcelColumnName(int columnNumber)
{
    int dividend = columnNumber;
    string columnName = String.Empty;
    int modulo;

    while (dividend > 0)
    {
        modulo = (dividend - 1) % 26;
        columnName = Convert.ToChar(65 + modulo).ToString() + columnName;
        dividend = (int)((dividend - modulo) / 26);
    }

    return columnName;
}

Below two methods were reused from: https://msdn.microsoft.com/en-us/library/office/cc861607.aspx

private static int InsertSharedStringItem(string text, SharedStringTablePart shareStringPart)
{
    // If the part does not contain a SharedStringTable, create one.
    if (shareStringPart.SharedStringTable == null)
    {
        shareStringPart.SharedStringTable = new SharedStringTable();
    }

    int i = 0;
    // Iterate through all the items in the SharedStringTable. If the text already exists, return its index.
    foreach (SharedStringItem item in shareStringPart.SharedStringTable.Elements<SharedStringItem>())
    {
        if (item.InnerText == text)
        {
            return i;
        }

        i++;
    }
    // The text does not exist in the part. Create the SharedStringItem and return its index.
    shareStringPart.SharedStringTable.AppendChild(new SharedStringItem(new DocumentFormat.OpenXml.Spreadsheet.Text(text)));
    shareStringPart.SharedStringTable.Save();

    return i;
}

// Given a column name, a row index, and a WorksheetPart, inserts a cell into the worksheet. 
// If the cell already exists, returns it. 
private static Cell InsertCellInWorksheet(string columnName, int rowIndex, WorksheetPart worksheetPart)
{
    Worksheet worksheet = worksheetPart.Worksheet;
    SheetData sheetData = worksheet.GetFirstChild<SheetData>();
    string cellReference = columnName + rowIndex;

    // If the worksheet does not contain a row with the specified row index, insert one.
    Row row = null;
    if (sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).Count() != 0)
    {
        row = sheetData.Elements<Row>().Where(r => r.RowIndex == rowIndex).First();
    }
    else
    {
        row = new Row() { RowIndex = (uint)rowIndex };
        sheetData.InsertAt(new Row(), rowIndex);
    }

    // If there is not a cell with the specified column name, insert one.  
    if (row.Elements<Cell>().Where(c => c.CellReference.Value == columnName + rowIndex).Count() > 0)
    {
        return row.Elements<Cell>().Where(c => c.CellReference.Value == cellReference).First();
    }
    else
    {
        // Cells must be in sequential order according to CellReference. Determine where to insert the new cell.
        Cell refCell = null;
        foreach (Cell cell in row.Elements<Cell>())
        {
            if (string.Compare(cell.CellReference.Value, cellReference, true) > 0)
            {
                refCell = cell;
                break;
            }
        }
        Cell newCell = new Cell() { CellReference = cellReference };
        row.InsertBefore(newCell, refCell);

        worksheetPart.Worksheet.Save();
        return newCell;
    }
}

Then you need to add an extension Method for Adding new row with styles

public static class ExtensionClass
{
//A method for copying a row and insert it:
//Copy an existing row and insert it
//We don't need to copy styles of a refRow because a CloneNode() or Clone() methods do it for us
public static Row CopyToLine(this Row refRow, uint rowIndex, SheetData sheetData)
{
    uint newRowIndex;
    var newRow = (Row)refRow.CloneNode(true);        
    // Loop through all the rows in the worksheet with higher row 
    // index values than the one you just added. For each one,
    // increment the existing row index.
    IEnumerable<Row> rows = sheetData.Descendants<Row>().Where(r => r.RowIndex.Value >= rowIndex);
    foreach (Row row in rows)
    {
        newRowIndex = System.Convert.ToUInt32(row.RowIndex.Value + 1);
        foreach (Cell cell in row.Elements<Cell>())
        {
            // Update the references for reserved cells.
           string cellReference = cell.CellReference.Value;
           cell.CellReference = new StringValue(cellReference.Replace(row.RowIndex.Value.ToString(), newRowIndex.ToString()));
           cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
        }
        // Update the row index.
        row.RowIndex = new UInt32Value(newRowIndex);
    }         
    sheetData.InsertBefore(newRow, refRow);
    return newRow;
   }
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.