Adding multiple Cells to a single Row - c#

I am new to this and when I try to add more than one cell to a row it says there is unreadable content. Here is what I have.
SpreadsheetDocument ssDoc = SpreadsheetDocument.Create(saveFile, SpreadsheetDocumentType.Workbook);
// Add a WorkbookPart to the document
WorkbookPart workbookPart = ssDoc.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
// Add a WorksheetPart to theWorkbookPart
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
Sheets sheets = ssDoc.WorkbookPart.Workbook.AppendChild<Sheets>(new Sheets());
Sheet sheet = new Sheet()
{ Id = ssDoc.WorkbookPart.GetIdOfPart(worksheetPart),
SheetId = 1, Name = "Sheet1"
};
sheets.Append(sheet);
Worksheet worksheet = new Worksheet();
SheetData sheetData = new SheetData();
Row row = new Row();
Cell cell = new Cell()
{
CellReference = "A1",
DataType = CellValues.String,
CellValue = new CellValue("Cell1")
};
Cell cell2 = new Cell()
{
CellReference = "A2",
DataType = CellValues.String,
CellValue = new CellValue("Cell2")
};
row.Append(cell);
row.Append(cell2);
sheetData.Append(row);
worksheet.Append(sheetData);
worksheetPart.Worksheet = worksheet;
// Close the document.
ssDoc.Close();
If I remove the second cell, it works as expected.

Instead of "A2" the cell reference should be "B1"
SpreadSheet.Cell cell = new SpreadSheet.Cell()
{
CellReference = "A1",
DataType = SpreadSheet.CellValues.String,
CellValue = new SpreadSheet.CellValue("Cell1")
};
SpreadSheet.Cell cell2 = new SpreadSheet.Cell()
{
CellReference = "B1",
DataType = SpreadSheet.CellValues.String,
CellValue = new SpreadSheet.CellValue("Cell2")
};

I had a similar issue. If anyone wants to insert cells in the same column, Row Index needs to be incremented and cell reference in order to insert cell in the same column. Took me entire weekend to figure out :D
Row row2 = new Row { RowIndex = 2};
SpreadSheet.Cell cell2 = new SpreadSheet.Cell()
{
CellReference = "B1",
DataType = SpreadSheet.CellValues.String,
CellValue = new SpreadSheet.CellValue("Cell2")
};
row2.Append(cell2);
sheetData.Append(row);
It's better to use loop.

Related

Formatting dates and currency when exporting to Excel

I have some code that's creating a DataTable, and then converting it to an Excel spreadsheet. Code is below:
DataTable table = (DataTable)JsonConvert.DeserializeObject(JsonConvert.SerializeObject(exportDtos), typeof(DataTable));
using var stream = new MemoryStream();
using (SpreadsheetDocument document = SpreadsheetDocument.Create(stream, SpreadsheetDocumentType.Workbook))
{
WorkbookPart workbookPart = document.AddWorkbookPart();
workbookPart.Workbook = new Workbook();
WorksheetPart worksheetPart = workbookPart.AddNewPart<WorksheetPart>();
var sheetData = new SheetData();
worksheetPart.Worksheet = new Worksheet(sheetData);
Sheets sheets = workbookPart.Workbook.AppendChild(new Sheets());
Sheet sheet = new Sheet() { Id = workbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Sheet1" };
sheets.Append(sheet);
Row headerRow = new Row();
List<String> columns = new List<string>();
foreach (DataColumn column in table.Columns)
{
columns.Add(column.ColumnName);
Cell cell = new Cell();
cell.DataType = CellValues.String;
cell.CellValue = new CellValue(column.ColumnName);
headerRow.AppendChild(cell);
}
sheetData.AppendChild(headerRow);
foreach (DataRow dsrow in table.Rows)
{
Row newRow = new Row();
foreach (String col in columns)
{
Cell cell = new Cell();
var celltype = dsrow[col].GetType();
if (dsrow[col].GetType() == typeof(double))
{
cell.DataType = CellValues.Number;
cell.CellValue = new CellValue(decimal.Parse(dsrow[col].ToString()));
cell.StyleIndex = 2;
}
else if (dsrow[col].GetType() == typeof(DateTime))
{
cell.DataType = CellValues.Date;
cell.CellValue = new CellValue(DateTime.Parse(dsrow[col].ToString()).ToOADate());
cell.StyleIndex = 1;
}
else
{
cell.DataType = CellValues.String;
cell.CellValue = new CellValue(dsrow[col].ToString());
}
newRow.AppendChild(cell);
}
sheetData.AppendChild(newRow);
}
workbookPart.Workbook.Save();
}
The problem is that dates and decimal values were stored as text, and not sorting correctly in Excel, so I added these two conditions:
if (dsrow[col].GetType() == typeof(double))
{
cell.DataType = CellValues.Number;
cell.CellValue = new CellValue(decimal.Parse(dsrow[col].ToString()));
cell.StyleIndex = 2;
}
else if (dsrow[col].GetType() == typeof(DateTime))
{
cell.DataType = CellValues.Date;
cell.CellValue = new CellValue(DateTime.Parse(dsrow[col].ToString()).ToOADate());
cell.StyleIndex = 1;
}
else
{
cell.DataType = CellValues.String;
cell.CellValue = new CellValue(dsrow[col].ToString());
}
There's a few problems:
The StyleIndex doesn't work for the double values, it's not formatting the cell with 2 decimal places. It also gives this Repair error:
We found a problem with some content in 'file.xlsx' ... Excel was able to open the file by repairing or removing the unreadable content.
Excel completed file level validation and repair. Some parts of this workbook may have been repaired or discarded.
If I remove the StyleIndex, I don't get the error, but it still doesn't format the cell with 2 decimal places.
The date value is always a number value, not a date. And it always gives the repair error.
I've looked at several different forums saying to try different things, and I can't get any of them to work. I've changed the StyleIndex to different suggested numbers, changed the DataType, and it's always the same problems. Is there a consistent answer to how to format dates and currency values?

OpenXML - How can I insert a value into a specific worksheet?

I'm fairly new to creating Excel spreadsheets in C# and I'm looking for advice.
I've spent 2 or 3 days now looking through documentation and blogs etc but I cannot seem to find an answer to a common task.
I need to insert a text value into a specific worksheet. I cant easily post my code at the moment but it appears to be an issue with every example I've seen of the definition of a sheet, it always gets the first child.
I need to iterate through all sheets and dependant on the sheet name then go and insert a value.
I.e. If the sheet name = "testA" then write TestA, if the sheet name = "testB" then write "TestB".
Currently I can insert a value for the workbook but it inserts the same value for every sheet.
Sheets sheets = workbookPart.Workbook.GetFirstChild<Sheets>();
[Microsoft documentation] (https://learn.microsoft.com/en-us/office/open-xml/how-to-insert-text-into-a-cell-in-a-spreadsheet)
Please note I'm not just giving up on this I've just reached a bit of a wall with it and need some pointers.
Many Thanks, J
Namespaces I'm using:
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Packaging;
using DocumentFormat.OpenXml.Spreadsheet;
private void btnExport_Click(object sender, EventArgs e)
{
//Using Microsofts Interop class to create Excel files gives mixed resuts and requires excel to be installed.
// This uses OpenXML library to achieve this and doesnt require excel to be installed: https://medium.com/swlh/openxml-sdk-brief-guide-c-7099e2391059
string filepath = "Test.xlsx";
// Create a spreadsheet document by supplying the filepath.
// By default, AutoSave = true, Editable = true, and Type = xlsx.
SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.
Create(filepath, SpreadsheetDocumentType.Workbook);
// Add a WorkbookPart to the document.
WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
workbookpart.Workbook = new Workbook();
// Add a WorksheetPart to the WorkbookPart.
WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new Worksheet(new SheetData());
// Add Sheets to the Workbook.
Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.
AppendChild<Sheets>(new Sheets());
// Append a new worksheet and associate it with the workbook.
Sheet sheetOne = new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.
GetIdOfPart(worksheetPart),
SheetId = 1,
Name = "Sheet1"
};
Sheet sheetTwo= new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.
GetIdOfPart(worksheetPart),
SheetId = 2,
Name = "Sheet2"
};
Sheet sheetParameters = new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.
GetIdOfPart(worksheetPart),
SheetId = 3,
Name = "Parameters"
};
Sheet sheetFour= new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.
GetIdOfPart(worksheetPart),
SheetId = 4,
Name = "Sheet4"
};
Sheet sheetFive= new Sheet()
{
Id = spreadsheetDocument.WorkbookPart.
GetIdOfPart(worksheetPart),
SheetId = 5,
Name = "Sheet5"
};
sheets.Append(sheetOne);
sheets.Append(sheetTwo);
sheets.Append(sheetParameters);
sheets.Append(sheetFour);
sheets.Append(sheetFive);
workbookpart.Workbook.Save();
// Close the document.
spreadsheetDocument.Close();
//InsertTextExistingExcel(filepath, "test1", "A", 1, "Parameters");
InsertInSheet(filepath, "test1", "A", 1, "Parameters");
//Any of these lists empty?
}
public static void InsertInSheet(string filePath, string value, string columnName, uint rowIndex, string sheetName)
{
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(filePath, true))
{
getSheetDetails(spreadSheet);
}
}
//work here
public static void getSheetDetails(SpreadsheetDocument doc)
{
WorksheetPart worksheetPart;
//iterate through sheets
foreach (Sheet sheetDetail in doc.WorkbookPart.Workbook.Sheets)
{
if (sheetDetail.Name == "Parameters")
{
//each sheet has a worksheetPart
worksheetPart = (WorksheetPart)doc.WorkbookPart.GetPartById(sheetDetail.Id);
Cell cell = InsertCellInWorksheet("A", 1, worksheetPart);
cell.CellValue = new CellValue("test");
cell.DataType = new EnumValue<CellValues>(CellValues.String);
worksheetPart.Worksheet.Save();
}
}
}
private static Cell InsertCellInWorksheet(string columnName, uint rowIndex, WorksheetPart worksheetPart)
{
//fix earlier worksheetPart only has a count of 1
Worksheet worksheet = worksheetPart.Worksheet;
//fix this to point to sheet
//SheetData sheetData = worksheet.Descendants<SheetData>();
SheetData sheetData = worksheet.GetFirstChild<SheetData>();
MessageBox.Show(sheetData.InnerXml.ToString());
string cellReference = columnName + rowIndex;
Row row;
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 = rowIndex };
sheetData.Append(row);
}
Cell refCell = row.Descendants<Cell>().LastOrDefault();
Cell newCell = new Cell() { CellReference = cellReference };
row.InsertAfter(newCell, refCell);
worksheet.Save();
return newCell;
}

Create Merge Cells using OpenXML

Please consider this Excel:
and it's XML:
I want to create such this Excel that has multiple merged cells using OpenXML.
How I can do this?
thanks
You can use the MergeCells and MergeCell classes to create the merged cells you require. The MergeCells class is the collection of merge cells (<mergeCells count="3"> in your XML) and the MergeCell class represents each individual set of merged cells (<mergeCell ref="xx:xx" /> in your XML). To populate data in the merged cells you need to add the value to the upper left most cell; any other values will be ignored.
The following code will create a new file with merged cells.
using (SpreadsheetDocument myDoc = SpreadsheetDocument.Create(filename, SpreadsheetDocumentType.Workbook))
{
WorkbookPart workbookpart = myDoc.AddWorkbookPart();
workbookpart.Workbook = new Workbook();
// Add a WorksheetPart to the WorkbookPart.
WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
SheetData sheetData = new SheetData();
//add a row
Row firstRow = new Row();
firstRow.RowIndex = (UInt32)1;
//create a cell in C1 (the upper left most cell of the merged cells)
Cell dataCell = new Cell();
dataCell.CellReference = "C1";
CellValue cellValue = new CellValue();
cellValue.Text = "99999";
dataCell.Append(cellValue);
firstRow.AppendChild(dataCell);
sheetData.AppendChild(firstRow);
// Add a WorkbookPart to the document.
worksheetPart.Worksheet = new Worksheet(sheetData);
//create a MergeCells class to hold each MergeCell
MergeCells mergeCells = new MergeCells();
//append a MergeCell to the mergeCells for each set of merged cells
mergeCells.Append(new MergeCell() { Reference = new StringValue("C1:F1") });
mergeCells.Append(new MergeCell() { Reference = new StringValue("A3:B3") });
mergeCells.Append(new MergeCell() { Reference = new StringValue("G5:K5") });
worksheetPart.Worksheet.InsertAfter(mergeCells, worksheetPart.Worksheet.Elements<SheetData>().First());
//this is the part that was missing from your code
Sheets sheets = myDoc.WorkbookPart.Workbook.AppendChild(new Sheets());
sheets.AppendChild(new Sheet()
{
Id = myDoc.WorkbookPart.GetIdOfPart(myDoc.WorkbookPart.WorksheetParts.First()),
SheetId = 1,
Name = "Sheet1"
});
}
The code above produces:

How to insert text in existing Cell?

I am trying to insert the text in existing cell by OpenXml, but it's not reflecting the excel sheet, Please any help me to!
static void InsertTextInCell(WorksheetPart worksheetPart)
{
Worksheet workSheet = worksheetPart.Worksheet;
SheetData sheetData = workSheet.GetFirstChild<SheetData>();
Cell cell = new Cell()
{
CellReference = "E8",
DataType = CellValues.String,
CellValue = new CellValue("Adding Value")
};
sheetData.Append(cell);
}
or
static void InsertTextInCell(WorkbookPart wbPart, string sheetName)
{
Sheet theSheet = wbPart.Workbook.Descendants<Sheet>().
Where(s => s.Name == sheetName).FirstOrDefault();
WorksheetPart wsPart =
(WorksheetPart)(wbPart.GetPartById(theSheet.Id));
Cell theCell = wsPart.Worksheet.Descendants<Cell>().
Where(c => c.CellReference == "A8").FirstOrDefault();
CellValue cellValue2 = new CellValue();
cellValue2.Text = "1test";
theCell.Append(cellValue2);
}
Thanks,
Saran
You can refer below code snippet to insert in text in excel
// Creates an SheetData instance and adds its children.
public SheetData GenerateSheetData()
{
SheetData sheetData1 = new SheetData();
Row row1 = new Row(){ RowIndex = (UInt32Value)1U, Spans = new ListValue<StringValue>() { InnerText = "1:1" } };
Cell cell1 = new Cell(){ CellReference = "A1", DataType = CellValues.SharedString };
CellValue cellValue1 = new CellValue();
cellValue1.Text = "0";
cell1.Append(cellValue1);
row1.Append(cell1);
Row row2 = new Row(){ RowIndex = (UInt32Value)2U, Spans = new ListValue<StringValue>() { InnerText = "1:1" } };
Cell cell2 = new Cell(){ CellReference = "A2", DataType = CellValues.SharedString };
CellValue cellValue2 = new CellValue();
cellValue2.Text = "1";
cell2.Append(cellValue2);
row2.Append(cell2);
sheetData1.Append(row1);
sheetData1.Append(row2);
return sheetData1;
}
static void InsertTextInCell(WorkbookPart wbPart, string sheetName, string addressName)
{
Sheet theSheet = wbPart.Workbook.Descendants<Sheet>().
Where(s => s.Name == sheetName).FirstOrDefault();
WorksheetPart wsPart =
(WorksheetPart)(wbPart.GetPartById(theSheet.Id));
Cell theCell = wsPart.Worksheet.Descendants<Cell>().
Where(c => c.CellReference == addressName).FirstOrDefault();
if (theCell.DataType == null)
{
theCell.CellValue = new CellValue("AddString");
}
}

Setting Font.Bold and Column.Width for Cells in OPEN XML

I've been using OPEN XML to create a spread sheet which can then be downloaded. I want to set the column widths and also change the header to bold. I've done this using Office.Interop.Excel but I'm struggling with this format. My code is below, you can see I've set up a font but have been unable to assign it to my spread sheet, I have got messages saying it's not possible to assign to a tree.
SpreadsheetDocument spreadsheetDocument = SpreadsheetDocument.Create(fileName, SpreadsheetDocumentType.Workbook); //Open(fileName, true);
try
{
WorkbookPart workbookpart = spreadsheetDocument.AddWorkbookPart();
workbookpart.Workbook = new DocumentFormat.OpenXml.Spreadsheet.Workbook();
WorksheetPart worksheetPart = workbookpart.AddNewPart<WorksheetPart>();
worksheetPart.Worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet(new SheetData());
DocumentFormat.OpenXml.Spreadsheet.Sheets sheets = spreadsheetDocument.WorkbookPart.Workbook.AppendChild<DocumentFormat.OpenXml.Spreadsheet.Sheets>(new DocumentFormat.OpenXml.Spreadsheet.Sheets());
Sheet sheet = new Sheet() { Id = spreadsheetDocument.WorkbookPart.GetIdOfPart(worksheetPart), SheetId = 1, Name = "Models" };
sheets.Append(sheet);
DocumentFormat.OpenXml.Spreadsheet.Font boldFont = new DocumentFormat.OpenXml.Spreadsheet.Font();
Bold bFontBold = new Bold();
boldFont.Append(bFontBold);
DocumentFormat.OpenXml.Spreadsheet.Worksheet worksheet = new DocumentFormat.OpenXml.Spreadsheet.Worksheet();
SheetData sheetData = new SheetData();
........
Row row = new Row();
Cell cell = new Cell()
{
CellReference = "A" + (intI + 1),
DataType = CellValues.String,
CellValue = new CellValue(ModelBookrowDetail[0])
};
row.Append(cell);
Cell cell2 = new Cell()
{
CellReference = "B" + (intI + 1),
DataType = CellValues.String,
CellValue = new CellValue(ModelBookrowDetail[1])
};
row.Append(cell2);
.........
sheetData.Append(row);
}
worksheet.Append(sheetData);
worksheetPart.Worksheet = worksheet;
spreadsheetDocument.Close();
}
catch
{
spreadsheetDocument.Close();
}
I don't know how set you are on using OpenXml. I might suggest looking into ClosedXml. Up until now it has saved me a lot of manhours. It only has one downside to it, and that is that it doesn't manage Word documents like OpenXml does.
ClosedXml is a more object oriented Open Source Library, and is far more well documented in contrast to what i have experienced with OpenXml.
You can find ClosedXml here:
https://github.com/ClosedXML/ClosedXML
Best of luck
Olliver

Categories