Unable to insert cells into an Open XML document as the OpenXml Excel document. I think the issue is that the cell.Remove() isn't actually clearing cell. I'm unsure because the document says that it has been modified
public static void InsertCell(uint rowIndex, int columnIndex, string value, SheetData sheetData, bool appendRow, EnumValue<CellValues> dataType = null, uint? styleIndex = null)
{
//Row row = null;
// Check if the worksheet contains a row with the specified row index.
var row = sheetData.Elements<Row>().FirstOrDefault(r => r.RowIndex == rowIndex);
if (row == null)
{
row = new Row() { RowIndex = rowIndex };
sheetData.Append(row);
}
// Convert column index to column name for cell reference.
var columnName = GetExcelColumnName(columnIndex);
var cellReference = columnName + rowIndex; // e.g. A1
// Check if the row contains a cell with the specified column name.
var cell = row.Elements<Cell>().FirstOrDefault(c => c.CellReference.Value == cellReference);
//We need to delete the cell if it does exist as the InsertAt function does not delete the existing cell if it has been found
if (cell != null)
{
cell.Remove();
//cell.CellValue.Remove();
}
if (cell == null || cell.CellValue == null)
{
if (dataType == null)
dataType = new EnumValue<CellValues>(CellValues.SharedString);
var newCell = new Cell() { CellReference = cellReference, CellValue = new CellValue(value), DataType = dataType };
if (styleIndex != null)
newCell.StyleIndex = styleIndex;
if (row.ChildElements.Count < columnIndex)
row.AppendChild(newCell);
else
row.InsertAt(newCell, (int)columnIndex);
}
}
Just for reference this is the calling code.
public static string AddToMaterialsRegister(SpreadsheetDocument spreadsheetDocument, com.upvise.client.Query query, JSONObject[] forms)
{
WorkbookPart workbookPart = spreadsheetDocument.WorkbookPart;
WorksheetPart worksheetPart = workbookPart.WorksheetParts.First();
SheetData sheetData = worksheetPart.Worksheet.Elements<SheetData>().First();
Stylesheet styleSheet = workbookPart.WorkbookStylesPart.Stylesheet;
var stringTable = workbookPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
string text = "";
uint currentRow = GetLastUsedRow(sheetData);
for (int i = 0; i < forms.Length; i += 1)
{
long epochDate = forms[i].getLong("date");
epochDate += 10 * 60 * 60 * 1000; //Add 10 hours to get to the QLD timezone
//The date from the form + 1970
epochDate = (epochDate / 1000 / 60 / 60 / 24) + 25569;
JObject customObj = JObject.Parse(forms[i].getString("value"));
string amount = (string)customObj["F4"];
if (!amount.Equals("") && amount != null)
{
switch ((string)customObj["F5"])
{
case "1":
amount += "T";
break;
case "0":
amount += "m3";
break;
}
}
else
amount = "";
// Not important
string tipValue = forms[i].getString("templateid") == "" ? (string)customObj["F18"] : (string)customObj["F19"];
//Grab the photos from the form
var files = query.selectFiles("Forms.forms", forms[i].getString("id") + ":F22");
//int dateIndex = InsertSharedStringItem(epochDate.ToString(), stringTable);
int materialIndex = InsertSharedStringItem((string)customObj["F1"], stringTable);
int amountIndex = InsertSharedStringItem(amount, stringTable);
int deliveredIndex = InsertSharedStringItem((string)customObj["F6"] + " " + (tipValue != null ? tipValue : ""), stringTable);
int certIndex = InsertSharedStringItem(files.Length > 0 ? "Y" : "", stringTable);
int formNameIndex = InsertSharedStringItem(forms[i].getString("name"), stringTable);
InsertCell(currentRow, 1, epochDate.ToString(), sheetData, false, new EnumValue<CellValues>(CellValues.Number), 2);
InsertCell(currentRow, 2, materialIndex.ToString(), sheetData, false, new EnumValue<CellValues>(CellValues.SharedString), 3);
InsertCell(currentRow, 3, amountIndex.ToString(), sheetData, false, new EnumValue<CellValues>(CellValues.SharedString), 3);
InsertCell(currentRow, 4, deliveredIndex.ToString(), sheetData, false, new EnumValue<CellValues>(CellValues.SharedString), 4);
InsertCell(currentRow, 5, certIndex.ToString(), sheetData, false, new EnumValue<CellValues>(CellValues.SharedString), 4);;
InsertCell(currentRow, 6, formNameIndex.ToString(), sheetData, true, new EnumValue<CellValues>(CellValues.SharedString), 4);
currentRow += 1;
}
//spreadsheetDocument.Save();
//spreadsheetDocument.Close();
//worksheetPart.Worksheet.Save();
//workbookPart.Workbook.Save();
return forms.Length + " forms were added";
}
When I run the code it does not add rows to the xlsx.
Any help would be greatly appreciated.
I commented out the Row row = null; as that has wiping the row every time I inserted a new cell.
Related
I'm using NPOI library to create excel file, I have problem with formatting price.
ISheet excelSheet = workbook.CreateSheet(sheetName);
ICellStyle codeCellStyle = workbook.CreateCellStyle();
ICellStyle priceCellStyle = workbook.CreateCellStyle();
ICellStyle availabilityStyle = workbook.CreateCellStyle();
excelSheet.SetColumnWidth(0, 10 * 256);
excelSheet.SetColumnWidth(1, 12 * 256);
excelSheet.SetColumnWidth(2, 15 * 256);
List<string> columns = new List<string>() { "Code", "Price", "Availability" };
IRow row = excelSheet.CreateRow(0);
foreach (var columnData in columns.Select((v, i) => new { Column = v, Index = i }).ToList())
{
row.CreateCell(columnData.Index).SetCellValue(columnData.Column);
}
codeCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("#");
priceCellStyle.DataFormat = workbook.CreateDataFormat().GetFormat("#,##0.00");
availabilityStyle.DataFormat = workbook.CreateDataFormat().GetFormat("#");
int rowIndex = 1;
foreach (var item in items)
{
row = excelSheet.CreateRow(rowIndex);
row.CreateCell(0).SetCellValue(item.Code);
row.Cells[0].CellStyle = codeCellStyle;
if (item.HasData)
{
if (item.Price == "ON DEMAND")
{
row.CreateCell(1).SetCellValue(item.Price);
}
else
{
ICell priceCell = row.CreateCell(1);
row.Cells[1].SetCellType(CellType.Numeric);
row.Cells[1].CellStyle = priceCellStyle;
if (percentage != 0)
priceCell.SetCellValue(double.Parse(item.Price) + ((double)percentage / (double)100) * double.Parse(item.Price));
else
priceCell.SetCellValue(double.Parse(item.Price));
}
row.CreateCell(2).SetCellValue(item.Availability ? "True" : "False");
}
else
{
row.CreateCell(1).SetCellValue("");
row.CreateCell(2).SetCellValue("");
}
rowIndex++;
}
When I have item with price "422,26" it produce excel file with price value 42226,00.
It works fine when I have price "380,00", "4730,00", but problem occurs when I have decimal part in string number.
I tried other suggestions from stackoverflow but I have no luck nothing works on my example.
After struggling this format solved my problem
"#,#0.00"
I am using C# with Open XML Format SDK 2.0, Trying to write an Excel report file. My problem is when I cross the Z column (reaching AA) the file goes corrupted and cannot be open manually by the user.
Any ideas?
static void Main(string[] args)
{
PortfolioReport report = new PortfolioReport("Keywords");
report.CreateReport();
}
public PortfolioReport(string client)
{
string newFileName = path + client + ".xlsx";
if (File.Exists(newFileName))
{
File.Delete(newFileName);
}
FileInfo newFile = new FileInfo(newFileName);
using (ExcelPackage package = new ExcelPackage(newFile))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets.Add("Keywords");
package.Save();
}
document = SpreadsheetDocument.Open(newFileName, true);
wbPart = document.WorkbookPart;
}
static readonly string[] Columns = new[] { "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "AA", "AB", "AC", "AD", "AE", "AF", "AG", "AH", "AI", "AJ", "AK", "AL", "AM", "AN", "AO", "AP", "AQ", "AR", "AS", "AT", "AU", "AV", "AW", "AX", "AY", "AZ", "BA", "BB", "BC", "BD", "BE", "BF", "BG", "BH" };
public static string IndexToColumn(int index)
{
if (index < 0)
throw new IndexOutOfRangeException("index must be a positive number");
return Columns[index];
}
public static object GetPropValue(object src, string propName)
{
return src.GetType().GetProperty(propName).GetValue(src, null);
}
// Create a new Portfolio report
public void CreateReport()
{
string wsName = "Report Summary";
wbPart.Workbook.Descendants<Sheet>().FirstOrDefault().Name = wsName;
var currentUser = UsersInfo.Keywords;
//set the domainAge
KeywordsModule.SetYearsAndMonths(currentUser.Keywords);
//set the url site relevency in words
KeywordsModule.SetAverageUrlSiteRelevencyLiteral(currentUser.Keywords);
//set a model for the excel which will convert the keyword to the custom model according to gui names
List<KeywordModelForExcelExport> keywordsForExports = KeywordsModule.PrepreKeywordSforExport(currentUser.Keywords);
//we set the column headings
var properties = typeof(KeywordModelForExcelExport).GetProperties();
for (int i = 0; i < properties.Length; i++)
{
var cell = IndexToColumn(i) + 1;
UpdateValue(wsName, cell, properties[i].Name, 0, true);
}
//now we set the keyword values
int row = 2;
foreach (var keywordForExport in keywordsForExports)
{
for (int i = 0; i < properties.Length; i++)
{
var val = GetPropValue(keywordForExport, properties[i].Name);
var cell = IndexToColumn(i) + row;
if (val != null)
UpdateValue(wsName, cell, val.ToString(), 0, true);
}
row++;
}
// All done! Close and save the document.
document.Close();
}
// Given a Worksheet and an address (like "AZ254"), either return a cell reference, or
// create the cell reference and return it.
private Cell InsertCellInWorksheet(Worksheet ws, string addressName)
{
SheetData sheetData = ws.GetFirstChild<SheetData>();
Cell cell = null;
UInt32 rowNumber = GetRowIndex(addressName);
Row row = GetRow(sheetData, rowNumber);
// If the cell you need already exists, return it.
// If there is not a cell with the specified column name, insert one.
Cell refCell = row.Elements<Cell>().
Where(c => c.CellReference.Value == addressName).FirstOrDefault();
if (refCell != null)
{
cell = refCell;
}
else
{
cell = CreateCell(row, addressName);
}
return cell;
}
private Cell CreateCell(Row row, String address)
{
Cell cellResult;
Cell refCell = null;
// Cells must be in sequential order according to CellReference. Determine where to insert the new cell.
foreach (Cell cell in row.Elements<Cell>())
{
if (string.Compare(cell.CellReference.Value, address, true) > 0)
{
refCell = cell;
break;
}
}
cellResult = new Cell();
cellResult.CellReference = address;
row.InsertBefore(cellResult, refCell);
return cellResult;
}
private Row GetRow(SheetData wsData, UInt32 rowIndex)
{
var row = wsData.Elements<Row>().
Where(r => r.RowIndex.Value == rowIndex).FirstOrDefault();
if (row == null)
{
row = new Row();
row.RowIndex = rowIndex;
wsData.Append(row);
}
return row;
}
private UInt32 GetRowIndex(string address)
{
string rowPart;
UInt32 l;
UInt32 result = 0;
for (int i = 0; i < address.Length; i++)
{
if (UInt32.TryParse(address.Substring(i, 1), out l))
{
rowPart = address.Substring(i, address.Length - i);
if (UInt32.TryParse(rowPart, out l))
{
result = l;
break;
}
}
}
return result;
}
public bool UpdateValue(string sheetName, string addressName, string value, UInt32Value styleIndex, bool isString)
{
// Assume failure.
bool updated = false;
Sheet sheet = wbPart.Workbook.Descendants<Sheet>().Where((s) => s.Name == sheetName).FirstOrDefault();
if (sheet != null)
{
Worksheet ws = ((WorksheetPart)(wbPart.GetPartById(sheet.Id))).Worksheet;
Cell cell = InsertCellInWorksheet(ws, addressName);
if (isString)
{
// Either retrieve the index of an existing string,
// or insert the string into the shared string table
// and get the index of the new item.
int stringIndex = InsertSharedStringItem(wbPart, value);
cell.CellValue = new CellValue(stringIndex.ToString());
cell.DataType = new EnumValue<CellValues>(CellValues.SharedString);
}
else
{
cell.CellValue = new CellValue(value);
cell.DataType = new EnumValue<CellValues>(CellValues.Number);
}
if (styleIndex > 0)
cell.StyleIndex = styleIndex;
// Save the worksheet.
ws.Save();
updated = true;
}
return updated;
}
// Given the main workbook part, and a text value, insert the text into the shared
// string table. Create the table if necessary. If the value already exists, return
// its index. If it doesn't exist, insert it and return its new index.
private int InsertSharedStringItem(WorkbookPart wbPart, string value)
{
int index = 0;
bool found = false;
var stringTablePart = wbPart.GetPartsOfType<SharedStringTablePart>().FirstOrDefault();
// If the shared string table is missing, something's wrong.
// Just return the index that you found in the cell.
// Otherwise, look up the correct text in the table.
if (stringTablePart == null)
{
// Create it.
stringTablePart = wbPart.AddNewPart<SharedStringTablePart>();
stringTablePart.SharedStringTable = new SharedStringTable();
}
var stringTable = stringTablePart.SharedStringTable;
// if (stringTable == null)
// {
// stringTable = new SharedStringTable();
// }
// Iterate through all the items in the SharedStringTable. If the text already exists, return its index.
foreach (SharedStringItem item in stringTable.Elements<SharedStringItem>())
{
if (item.InnerText == value)
{
found = true;
break;
}
index += 1;
}
if (!found)
{
stringTable.AppendChild(new SharedStringItem(new Text(value)));
stringTable.Save();
}
return index;
}
Your ordering is broken in CreateCell for cell references after Z. You are currently using string.Compare but that will do an alpha comparison meaning AA1 is before Z1 rather than after it.
There are various ways you could fix this - one way would be to convert the cellReference to a column index and then compare those instead of comparing the cell references directly. For example:
private static int? GetColumnIndex(string cellRef)
{
if (string.IsNullOrEmpty(cellRef))
return null;
cellRef = cellRef.ToUpper();
int columnIndex = -1;
int mulitplier = 1;
foreach (char c in cellRef.ToCharArray().Reverse())
{
if (char.IsLetter(c))
{
columnIndex += mulitplier * ((int)c - 64);
mulitplier = mulitplier * 26;
}
}
return columnIndex;
}
Then instead of
if (string.Compare(cell.CellReference.Value, address, true) > 0)
{
refCell = cell;
break;
}
You can do
if (GetColumnIndex(cell.CellReference.Value) > GetColumnIndex(address))
{
refCell = cell;
break;
}
I have a WPF application where I have functionality to read data from Excel.
I was doing this using OLEDB and it was working great, until I found out there was a 255 limit for columns and the data would be truncated unless data > 255 characters is not present in the first eight rows. Fix for this issue is to update the registry which would mean updating all users' registries. So I don't want to go with that approach.
OLEDB code:
string strSQL = "SELECT * FROM [Sheet1$]";
OleDbCommand cmd = new OleDbCommand(strSQL, conn);
DataSet ds1 = new DataSet();
OleDbDataAdapter da = new OleDbDataAdapter(cmd);
da.Fill(ds1);
As an alternative, I tried Interop.Excel . However, it seems to be slower that OLEDB. The Excel sheets that were taking 2 seconds to load take about 15 seconds using Interop.Excel.
System.Data.DataTable tempTable = new System.Data.DataTable();
tempTable.TableName = "ResultData";
Excel.Application app = new Excel.Application();
Excel.Workbook book = null;
Excel.Range range = null;
try
{
app.Visible = false;
app.ScreenUpdating = false;
app.DisplayAlerts = false;
book = app.Workbooks.Open(inputFilePath, Missing.Value, Missing.Value, Missing.Value
, Missing.Value, Missing.Value, Missing.Value, Missing.Value
, Missing.Value, Missing.Value, Missing.Value, Missing.Value
, Missing.Value, Missing.Value, Missing.Value);
foreach (Excel.Worksheet sheet in book.Worksheets)
{
Logger.LogException("Values for Sheet " + sheet.Index, System.Reflection.MethodBase.GetCurrentMethod().ToString());
// get a range to work with
range = sheet.get_Range("A1", Missing.Value);
// get the end of values to the right (will stop at the first empty cell)
range = range.get_End(Excel.XlDirection.xlToRight);
// get the end of values toward the bottom, looking in the last column (will stop at first empty cell)
range = range.get_End(Excel.XlDirection.xlDown);
// get the address of the bottom, right cell
string downAddress = range.get_Address(
false, false, Excel.XlReferenceStyle.xlA1,
Type.Missing, Type.Missing);
// Get the range, then values from a1
range = sheet.get_Range("A1", downAddress);
object[,] values = (object[,])range.Value2;
//Get the Column Names
for (int k = 0; k < values.GetLength(1); )
{
tempTable.Columns.Add(Convert.ToString(values[1, ++k]).Trim());
}
for (int i = 2; i <= values.GetLength(0); i++)//first row contains the column names, so start from the next row.
{
System.Data.DataRow dr = tempTable.NewRow();
for (int j = 1; j <= values.GetLength(1); j++)//columns
{
dr[j - 1] = values[i, j];
}
tempTable.Rows.Add(dr);
}
}
Is there another alternative which is as fast as OLEDB?
The columns and rows are not fixed in the Excel sheet.
If you are working with xlsx files I would recommend switching to the Open XML SDK for Office, it performs much better than OLEDB or the Interop methods of connecting.
However, some people consider the SDK difficult to use so there are 3rd party packages that will wrap up the SDK into a more friendly interface, but personally I don't find the SDK too hard to do.
Thank you for your response.Here is the final code that I used:
Reference link : http://www.prowareness.com/blog/reading-data-from-excel-document-using-openxml/
public static DataSet ExtractExcelSheetValuesToDataTable(string xlsxFilePath, string sheetName)
{
DataTable dt = new DataTable();
DataSet ds = new DataSet();
using (SpreadsheetDocument myWorkbook = SpreadsheetDocument.Open(xlsxFilePath, true))
{
//Access the main Workbook part, which contains data
WorkbookPart workbookPart = myWorkbook.WorkbookPart;
WorksheetPart worksheetPart = null;
if (!string.IsNullOrEmpty(sheetName))
{
Sheet ss = workbookPart.Workbook.Descendants<Sheet>().Where(s => s.Name == sheetName).SingleOrDefault<Sheet>();
worksheetPart = (WorksheetPart)workbookPart.GetPartById(ss.Id);
}
else
{
worksheetPart = workbookPart.WorksheetParts.FirstOrDefault();
}
SharedStringTablePart stringTablePart = workbookPart.SharedStringTablePart;
if (worksheetPart != null)
{
Row lastRow = worksheetPart.Worksheet.Descendants<Row>().LastOrDefault();
Row firstRow = worksheetPart.Worksheet.Descendants<Row>().FirstOrDefault();
if (firstRow != null)
{
foreach (Cell c in firstRow.ChildElements)
{
string value = GetValue(c, stringTablePart);
dt.Columns.Add(value);
}
}
if (lastRow != null)
{
for (int i = 2; i <= lastRow.RowIndex; i++)
{
DataRow dr = dt.NewRow();
bool empty = true;
Row row = worksheetPart.Worksheet.Descendants<Row>().Where(r => i == r.RowIndex).FirstOrDefault();
int j = 0;
if (row != null)
{
foreach (Cell c in row.Descendants<Cell>())
{
int? colIndex = GetColumnIndex(((DocumentFormat.OpenXml.Spreadsheet.CellType)(c)).CellReference);
if (colIndex > j)
{
dr[j] = "";
j++;
}
//Get cell value
string value = GetValue(c, stringTablePart);
//if (!string.IsNullOrEmpty(value))
// empty = false;
dr[j] = value;
j++;
if (j == dt.Columns.Count)
break;
}
//foreach (Cell c in row.ChildElements)
//{
// //Get cell value
// string value = GetValue(c, stringTablePart);
// //if (!string.IsNullOrEmpty(value))
// // empty = false;
// dr[j] = value;
// j++;
// if (j == dt.Columns.Count)
// break;
//}
//if (empty)
// break;
dt.Rows.Add(dr);
}
}
}
}
}
ds.Tables.Add(dt);
return ds;
}
public static string GetValue(Cell cell, SharedStringTablePart stringTablePart)
{
if (cell.ChildElements.Count == 0) return null;
//get cell value
string value = cell.ElementAt(0).InnerText;//CellValue.InnerText;
//Look up real value from shared string table
if ((cell.DataType != null) && (cell.DataType == CellValues.SharedString))
value = stringTablePart.SharedStringTable.ChildElements[Int32.Parse(value)].InnerText;
return value;
}
private static int? GetColumnIndex(string cellReference)
{
if (string.IsNullOrEmpty(cellReference))
{
return null;
}
//remove digits
string columnReference = Regex.Replace(cellReference.ToUpper(), #"[\d]", string.Empty);
int columnNumber = -1;
int mulitplier = 1;
//working from the end of the letters take the ASCII code less 64 (so A = 1, B =2...etc)
//then multiply that number by our multiplier (which starts at 1)
//multiply our multiplier by 26 as there are 26 letters
foreach (char c in columnReference.ToCharArray().Reverse())
{
columnNumber += mulitplier * ((int)c - 64);
mulitplier = mulitplier * 26;
}
//the result is zero based so return columnnumber + 1 for a 1 based answer
//this will match Excel's COLUMN function
return columnNumber;
}
I am trying to insert data to multiple sheets. For my excel, I have two sheets which are "charts" and "ChartData". I'm able to update the data in sheet2, chartdata sheet, but I'm unable to insert data to sheet1. Here is code which I have tried to insert data into excel sheets. Here data is coming from database.
double ticks = DateTime.Now.Ticks;
// MarketAnalysis ms = new MarketAnalysis();
//ms.Marketanalysis();
File.Copy(Srcpath, #"E:\Works\OpenXML\DownloadTemplates\ExcelGenerated" + ticks + ".xlsx", true);
using (SpreadsheetDocument myworkbok = SpreadsheetDocument.Open(#"E:\Works\OpenXML\DownloadTemplates\ExcelGenerated" + ticks + ".xlsx", true))
{
//Acess the main workbook which contain all the references
WorkbookPart workbookpart = myworkbok.WorkbookPart;
//Get sheet by name
Sheet sheet = workbookpart.Workbook.Descendants<Sheet>().Where(s => s.Name == "ChartData").FirstOrDefault();
//Worksheet Part by ID
WorksheetPart worksheetpart = workbookpart.GetPartById(sheet.Id) as WorksheetPart;
//Sheet data contains all the data
SheetData sheetdata = worksheetpart.Worksheet.GetFirstChild<SheetData>();
DataSet ds = db.Chart1Data();
for (int i = 0; i < ds.Tables[0].Rows.Count; i++)
{
// if (ds.Tables[0].Rows !=DBNull)
//{
string Rowlabel = ds.Tables[0].Rows[i][0].ToString();
// float? FY13Actuval = Convert.ToInt32(ds.Tables[0].Rows[i][1]);
if (!string.IsNullOrEmpty(ds.Tables[0].Rows[i][1].ToString()))
{
// string s = ds.Tables[0].Rows[i][1].ToString();
//FY13Actuval=float.Parse(ds.Tables[0].Rows[i][1].ToString());
FY13Actuval = Convert.ToDouble(ds.Tables[0].Rows[i][1].ToString());
}
else
{
FY13Actuval = null;
}
double? Budget = Convert.ToDouble(ds.Tables[0].Rows[i][2].ToString());
double? Actuval = Convert.ToDouble(ds.Tables[0].Rows[i][3].ToString());
Row contentrow = CreateContentRow(index, Product, Actual, Budget, Forecast);
index++;
sheetdata.AppendChild(contentrow);
// }
}
.......Same code for the other 3 charts
Sheet sheet1 = workbookpart.Workbook.Descendants<Sheet>().Where(s => s.Name == "Charts").FirstOrDefault();
WorksheetPart worksheetpart1 = workbookpart.GetPartById(sheet1.Id) as WorksheetPart;
//Sheet data contains all the data
SheetData sheetdata1 = worksheetpart1.Worksheet.GetFirstChild<SheetData>();
DataSet dsTbl = db.Table();
int SCMTblIndex=5;
for (int i = 0; i < dsTbl.Tables[0].Rows.Count; i++)
{
Row tblRow = CreateScorecardMetricTblRow(SCMTblIndex, dsTbl.Tables[0].Rows[i][0].ToString(),
dsTbl.Tables[0].Rows[i][1].ToString(),
dsTbl.Tables[0].Rows[i][2].ToString());
SCMTblIndex++;
sheetdata1.AppendChild(tblRow);
}
myworkbok.WorkbookPart.Workbook.Save();
}
and the Methods to create the cells:
public static string[] headerColumns = new string[]{ "A", "B", "C", "D", "E", "F", "G", "I", "J" };
public static string[] header = new string[] { "D", "E", "F" };
private static Row CreateContentRow(int index, string Product, double? Actual, double? Budget, double? Forecast)
{
//Create New ROw
Row r = new Row();
r.RowIndex = (UInt32)index;
//Begin colums
Cell c0 = new Cell();
c0.CellReference = headerColumns[0] + index;
CellValue v0 = new CellValue();
v0.Text = Product;
c0.AppendChild(v0);
r.AppendChild(c0);
Cell c1 = new Cell();
c1.CellReference = headerColumns[1] + index;
CellValue v1 = new CellValue();
v1.Text = Actual.ToString();
c1.AppendChild(v1);
r.AppendChild(c1);
Cell c2 = new Cell();
c2.CellReference = headerColumns[2] + index;
CellValue v2 = new CellValue();
v2.Text = Budget.ToString();
c2.AppendChild(v2);
r.AppendChild(c2);
Cell c3 = new Cell();
c3.CellReference = headerColumns[3] + index;
CellValue v3 = new CellValue();
v3.Text = Forecast.ToString();
c3.AppendChild(v3);
r.AppendChild(c3);
return r;
}
public static Row CreateScorecardMetricTblRow(int index, string Act_Data, string Bud_Data, string VarPr_Data)
{
Row r = new Row();
r.RowIndex = (UInt32)index;
//Begin Colums
Cell c0 = new Cell();
c0.CellReference = header[0] + index;
CellValue v0 = new CellValue();
v0.Text = Act_Data;
c0.AppendChild(v0);
r.AppendChild(c0);
Cell c1 = new Cell();
c1.CellReference = header[1] + index;
CellValue v1 = new CellValue();
v1.Text = Bud_Data;
c1.AppendChild(v1);
r.AppendChild(c1);
Cell c2 = new Cell();
c2.CellReference = header[2] + index;
CellValue v2 = new CellValue();
v2.Text = VarPr_Data;
c2.AppendChild(v2);
r.AppendChild(c2);
return r;
}
for multiple sheets to updated just
// Open the document for editing.
using (SpreadsheetDocument spreadSheet = SpreadsheetDocument.Open(docName, true))
{
// Insert code here.
}
create a two classes for two sheets which you need to update sheet cell values.For each class constructor pass the SpreadsheetDocument object and implement insert text into a cell in a spreadsheet document.Just avoid the code for insertion of new sheet and try the insertion of the cell code only.
You can try this method.....it may be helpful..
private static Cell InsertCellInWorksheet(string columnName, int rowIndex, WorksheetPart worksheetPart)
{
Worksheet worksheet = worksheetPart.Worksheet;
SheetData sheetData = worksheet.GetFirstChild<SheetData>();
string cellReference = columnName + rowIndex;
Alignment alignment1 = new Alignment() { WrapText = true };
// If the worksheet does not contain a row with the specified row index, insert one.
Row row;
row = new Row() { RowIndex = 3, StyleIndex = 1 };
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 = Convert.ToUInt32(rowIndex) };
sheetData.Append(row);
}
// 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)
{
Row row2;
row2 = new Row() { RowIndex = 3, StyleIndex = 1 };
Cell rCell = null;
foreach (Cell celld in row.Elements<Cell>())
{
if (string.Compare(celld.CellReference.Value, "A3", true) > 0)
{
rCell = celld;
break;
}
}
// Add the cell to the cell table at A1.
Cell newCell = new Cell() { CellReference = "C3" };
//Cell newCell1 = new Cell() { CellReference = "D3" };
row.InsertBefore(newCell, rCell);
//row.InsertBefore(newCell1, rCell);
// Set the cell value to be a numeric value of 100.
newCell.CellValue = new CellValue("#GUIDeXactLCMS#");
//newCell1.CellValue = new CellValue("EN");
newCell.DataType = new EnumValue<CellValues>(CellValues.Number);
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)
{
//string val = cell.CellReference.Value;
refCell = cell;
break;
}
}
Cell newCell = new Cell() { CellReference = cellReference };
row.InsertBefore(newCell, refCell);
return newCell;
}
worksheet.Save();
}
I'm using the following code to convert an Excel to a datatable using EPPlus:
public DataTable ExcelToDataTable(string path)
{
var pck = new OfficeOpenXml.ExcelPackage();
pck.Load(File.OpenRead(path));
var ws = pck.Workbook.Worksheets.First();
DataTable tbl = new DataTable();
bool hasHeader = true;
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
{
tbl.Columns.Add(hasHeader ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
}
var startRow = hasHeader ? 2 : 1;
for (var rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
var row = tbl.NewRow();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
tbl.Rows.Add(row);
}
pck.Dispose();
return tbl;
}
It creates the Excel, however, when I try to open it, it gives me the message that it is locked for editing by another user and that I can only open it in Read-Only mode.
I thought using:
pck.Dispose();
would solve the issue, however I'm still getting the same error.
Also, when I try to delete the file, I get the message: The action can't be completed because the file is open in WebDev.WebServer40.EXE.
Any ideas how to resolve this?
Thanks in advance. :)
I see, that's what i've posted recently here(now corrected). It can be improved since the ExcelPackage and the FileStream(from File.OpenRead) are not disposed after using.
public static DataTable GetDataTableFromExcel(string path, bool hasHeader = true)
{
using (var pck = new OfficeOpenXml.ExcelPackage())
{
using (var stream = File.OpenRead(path))
{
pck.Load(stream);
}
var ws = pck.Workbook.Worksheets.First();
DataTable tbl = new DataTable();
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
{
tbl.Columns.Add(hasHeader ? firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
}
var startRow = hasHeader ? 2 : 1;
for (int rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
DataRow row = tbl.Rows.Add();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
}
return tbl;
}
}
A extension version of Tim Schmelter's answer.
public static DataTable ToDataTable(this ExcelWorksheet ws, bool hasHeaderRow = true)
{
var tbl = new DataTable();
foreach (var firstRowCell in ws.Cells[1, 1, 1, ws.Dimension.End.Column])
tbl.Columns.Add(hasHeaderRow ?
firstRowCell.Text : string.Format("Column {0}", firstRowCell.Start.Column));
var startRow = hasHeaderRow ? 2 : 1;
for (var rowNum = startRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
var row = tbl.NewRow();
foreach (var cell in wsRow) row[cell.Start.Column - 1] = cell.Text;
tbl.Rows.Add(row);
}
return tbl;
}
I've created a method that converts an Excel file to a DataTable using EPPlus, and tried to maintain Type Safety. Also duplicate column names are handled and with a boolean you can tell the method wether the sheet has a row with headers. I've created it for a complex import process that has several steps after uploading that requires user input before committing to the database.
private DataTable ExcelToDataTable(byte[] excelDocumentAsBytes, bool hasHeaderRow)
{
DataTable dt = new DataTable();
string errorMessages = "";
//create a new Excel package in a memorystream
using (MemoryStream stream = new MemoryStream(excelDocumentAsBytes))
using (ExcelPackage excelPackage = new ExcelPackage(stream))
{
ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[1];
//check if the worksheet is completely empty
if (worksheet.Dimension == null)
{
return dt;
}
//add the columns to the datatable
for (int j = worksheet.Dimension.Start.Column; j <= worksheet.Dimension.End.Column; j++)
{
string columnName = "Column " + j;
var excelCell = worksheet.Cells[1, j].Value;
if (excelCell != null)
{
var excelCellDataType = excelCell;
//if there is a headerrow, set the next cell for the datatype and set the column name
if (hasHeaderRow == true)
{
excelCellDataType = worksheet.Cells[2, j].Value;
columnName = excelCell.ToString();
//check if the column name already exists in the datatable, if so make a unique name
if (dt.Columns.Contains(columnName) == true)
{
columnName = columnName + "_" + j;
}
}
//try to determine the datatype for the column (by looking at the next column if there is a header row)
if (excelCellDataType is DateTime)
{
dt.Columns.Add(columnName, typeof(DateTime));
}
else if (excelCellDataType is Boolean)
{
dt.Columns.Add(columnName, typeof(Boolean));
}
else if (excelCellDataType is Double)
{
//determine if the value is a decimal or int by looking for a decimal separator
//not the cleanest of solutions but it works since excel always gives a double
if (excelCellDataType.ToString().Contains(".") || excelCellDataType.ToString().Contains(","))
{
dt.Columns.Add(columnName, typeof(Decimal));
}
else
{
dt.Columns.Add(columnName, typeof(Int64));
}
}
else
{
dt.Columns.Add(columnName, typeof(String));
}
}
else
{
dt.Columns.Add(columnName, typeof(String));
}
}
//start adding data the datatable here by looping all rows and columns
for (int i = worksheet.Dimension.Start.Row + Convert.ToInt32(hasHeaderRow); i <= worksheet.Dimension.End.Row; i++)
{
//create a new datatable row
DataRow row = dt.NewRow();
//loop all columns
for (int j = worksheet.Dimension.Start.Column; j <= worksheet.Dimension.End.Column; j++)
{
var excelCell = worksheet.Cells[i, j].Value;
//add cell value to the datatable
if (excelCell != null)
{
try
{
row[j - 1] = excelCell;
}
catch
{
errorMessages += "Row " + (i - 1) + ", Column " + j + ". Invalid " + dt.Columns[j - 1].DataType.ToString().Replace("System.", "") + " value: " + excelCell.ToString() + "<br>";
}
}
}
//add the new row to the datatable
dt.Rows.Add(row);
}
}
//show error messages if needed
Label1.Text = errorMessages;
return dt;
}
The webforms button click for demo purposes.
protected void Button1_Click(object sender, EventArgs e)
{
if (FileUpload1.HasFile)
{
DataTable dt = ExcelToDataTable(FileUpload1.FileBytes, CheckBox1.Checked);
GridView1.DataSource = dt;
GridView1.DataBind();
}
}
VDWWD's answer above works great to keep type safety, and I built upon it with some improvements.
Method reads from a file directly.
Column type detection by using all rows and not just one value. Column type is set to String if more than type is found in the column.
Error Messages returned in a list of strings.
Here is the updated version:
public static DataTable ExcelToDataTable(string path, ref List<string> errorList, bool hasHeaderRow = true )
{
DataTable dt = new DataTable();
errorList = new List<string>();
//create a new Excel package
using (ExcelPackage excelPackage = new ExcelPackage())
{
using (var stream = File.OpenRead(path))
{
excelPackage.Load(stream);
}
ExcelWorksheet worksheet = excelPackage.Workbook.Worksheets[1];
//check if the worksheet is completely empty
if (worksheet.Dimension == null)
{
return dt;
}
//add the columns to the datatable
for (int j = worksheet.Dimension.Start.Column; j <= worksheet.Dimension.End.Column; j++)
{
string columnName = "Column " + j;
//Build hashset with all types in the row
var columnTypes = new HashSet<Type>();
for (int i = worksheet.Dimension.Start.Row + Convert.ToInt32(hasHeaderRow); i <= worksheet.Dimension.End.Row; i++)
{
//Only add type if cell value not empty
if (worksheet.Cells[i, j].Value != null)
{
columnTypes.Add(worksheet.Cells[i, j].Value.GetType());
}
}
var excelCell = worksheet.Cells[1, j].Value;
if (excelCell != null)
{
Type excelCellDataType = null;
//if there is a headerrow, set the next cell for the datatype and set the column name
if (hasHeaderRow == true)
{
columnName = excelCell.ToString();
//check if the column name already exists in the datatable, if so make a unique name
if (dt.Columns.Contains(columnName) == true)
{
columnName = columnName + "_" + j;
}
}
//Select input type for the column
if (columnTypes.Count == 1)
{
excelCellDataType = columnTypes.First();
}
else
{
excelCellDataType = typeof(string);
}
//try to determine the datatype for the column (by looking at the next column if there is a header row)
if (excelCellDataType == typeof(DateTime))
{
dt.Columns.Add(columnName, typeof(DateTime));
}
else if (excelCellDataType == typeof(Boolean))
{
dt.Columns.Add(columnName, typeof(Boolean));
}
else if (excelCellDataType == typeof(Double))
{
//determine if the value is a decimal or int by looking for a decimal separator
//not the cleanest of solutions but it works since excel always gives a double
if (excelCellDataType.ToString().Contains(".") || excelCellDataType.ToString().Contains(","))
{
dt.Columns.Add(columnName, typeof(Decimal));
}
else
{
dt.Columns.Add(columnName, typeof(Int64));
}
}
else
{
dt.Columns.Add(columnName, typeof(String));
}
}
else
{
dt.Columns.Add(columnName, typeof(String));
}
}
//start adding data the datatable here by looping all rows and columns
for (int i = worksheet.Dimension.Start.Row + Convert.ToInt32(hasHeaderRow); i <= worksheet.Dimension.End.Row; i++)
{
//create a new datatable row
DataRow row = dt.NewRow();
//loop all columns
for (int j = worksheet.Dimension.Start.Column; j <= worksheet.Dimension.End.Column; j++)
{
var excelCell = worksheet.Cells[i, j].Value;
//add cell value to the datatable
if (excelCell != null)
{
try
{
row[j - 1] = excelCell;
}
catch
{
errorList.Add("Row " + (i - 1) + ", Column " + j + ". Invalid " + dt.Columns[j - 1].DataType.ToString().Replace("System.", "") + " value: " + excelCell.ToString() );
}
}
}
//add the new row to the datatable
dt.Rows.Add(row);
}
}
return dt;
}
This is an improvement to the generic one above. Use is if you have a class with the following properties, "Name", "Surname", "Telephone", "Fax" and you have a excel sheet with the first row with the same names, it will load the excel rows into a class object and pop it into a List
public static List<T> GetClassFromExcel<T>(string path, int fromRow, int fromColumn, int toRow = 0, int toColumn = 0)
{
if (toColumn != 0 && toColumn < fromColumn) throw new Exception("toColumn can not be less than fromColumn");
if (toRow != 0 && toRow < fromRow) throw new Exception("toRow can not be less than fromRow");
List<T> retList = new List<T>();
using (var pck = new ExcelPackage())
{
using (var stream = File.OpenRead(path))
{
pck.Load(stream);
}
//Retrieve first Worksheet
var ws = pck.Workbook.Worksheets.First();
//If the to column is empty or 0, then make the tocolumn to the count of the properties
//Of the class object inserted
toColumn = toColumn == 0 ? typeof(T).GetProperties().Count() : toColumn;
//Read the first Row for the column names and place into a list so that
//it can be used as reference to properties
Dictionary<string, int> columnNames = new Dictionary<string, int>();
// wsRow = ws.Row(0);
var colPosition = 0;
foreach (var cell in ws.Cells[1, 1, 1, toColumn == 0 ? ws.Dimension.Columns : toColumn])
{
columnNames.Add(cell.Value.ToString(), colPosition);
colPosition++;
}
//create a instance of T
T objT = Activator.CreateInstance<T>();
//Retrieve the type of T
Type myType = typeof(T);
//Get all the properties associated with T
PropertyInfo[] myProp = myType.GetProperties();
//Loop through the rows of the excel sheet
for (var rowNum = fromRow; rowNum <= (toRow == 0? ws.Dimension.End.Row : toRow); rowNum++)
{
var wsRow = ws.Cells[rowNum, fromColumn, rowNum, ws.Cells.Count()];
foreach (var propertyInfo in myProp)
{
if (columnNames.ContainsKey(propertyInfo.Name))
{
int position = 0;
columnNames.TryGetValue(propertyInfo.Name, out position);
//int position = columnNames.IndexOf(propertyInfo.Name);
//To prevent an exception cast the value to the type of the property.
propertyInfo.SetValue(objT, Convert.ChangeType(wsRow[rowNum, position + 1].Value, propertyInfo.PropertyType));
}
}
retList.Add(objT);
}
}
return retList;
}
now you can use the list as a databinding source if you need...
A give from me to you... :) Daniel C. Vrey
Updated it for toColumn to work and added toRow and followed Andreas suggestions. Thumbs up for Andreas
public static List<T> getClassFromExcel<T>(string path, int fromRow, int fromColumn, int toColumn = 0) where T : class
{
using (var pck = new OfficeOpenXml.ExcelPackage())
{
List<T> retList = new List<T>();
using (var stream = File.OpenRead(path))
{
pck.Load(stream);
}
var ws = pck.Workbook.Worksheets.First();
toColumn = toColumn == 0 ? typeof(T).GetProperties().Count() : toColumn;
for (var rowNum = fromRow; rowNum <= ws.Dimension.End.Row; rowNum++)
{
T objT = Activator.CreateInstance<T>();
Type myType = typeof(T);
PropertyInfo[] myProp = myType.GetProperties();
var wsRow = ws.Cells[rowNum, fromColumn, rowNum, toColumn];
for (int i = 0; i < myProp.Count(); i++)
{
myProp[i].SetValue(objT, wsRow[rowNum, fromColumn + i].Text);
}
retList.Add(objT);
}
return retList;
}
}
public static List<T> GetClassFromExcel<T>(string path, int fromRow, int fromColumn, int toRow = 0, int toColumn = 0) where T: class, new()
{
if (toColumn != 0 && toColumn < fromColumn) throw new Exception("toColumn can not be less than fromColumn");
if (toRow != 0 && toRow < fromRow) throw new Exception("toRow can not be less than fromRow");
List<T> retList = new List<T>();
using (var pck = new ExcelPackage())
{
using (var stream = File.OpenRead(path))
{
pck.Load(stream);
}
//Retrieve first Worksheet
var ws = pck.Workbook.Worksheets.First();
toColumn = toColumn == 0 ? typeof(T).GetProperties().Count() : toColumn; //If the to column is empty or 0, then make the tocolumn to the count of the properties Of the class object inserted
//Read the first Row for the column names and place into a list so that
//it can be used as reference to properties
Dictionary<string, int> columnNames = new Dictionary<string, int>();
// wsRow = ws.Row(0);
var colPosition = 0;
foreach (var cell in ws.Cells[1, 1, 1, toColumn == 0 ? ws.Dimension.Columns : toColumn])
{
columnNames.Add(cell.Value.ToString(), colPosition);
colPosition++;
}
//Retrieve the type of T
Type myType = typeof(T);
//Get all the properties associated with T
PropertyInfo[] myProp = myType.GetProperties();
//Loop through the rows of the excel sheet
for (var rowNum = fromRow + 1; rowNum <= (toRow == 0 ? ws.Dimension.End.Row : toRow); rowNum++) // fromRow + 1 to read from next row after columnheader
{
//create a instance of T
//T objT = Activator.CreateInstance<T>();
T objT = new T();
// var wsRow = ws.Cells[rowNum, fromColumn, rowNum, ws.Cells.Count()]; //ws.Cells.Count() causing out of range error hence using ws.Dimension.Columns to get last column index
var wsRow = ws.Cells[rowNum, fromColumn, rowNum, ws.Dimension.Columns];
foreach (var propertyInfo in myProp)
{
var attribute = propertyInfo.GetCustomAttributes(typeof(DisplayNameAttribute), true).Cast<DisplayNameAttribute>().SingleOrDefault();
string displayName = attribute != null && !string.IsNullOrEmpty(attribute.DisplayName) ? attribute.DisplayName : propertyInfo.Name; // If DisplayName annotation not used then get property name itself
if (columnNames.ContainsKey(displayName))
{
int position = 0;
columnNames.TryGetValue(displayName, out position);
////int position = columnNames.IndexOf(propertyInfo.Name);
////To prevent an exception cast the value to the type of the property.
propertyInfo.SetValue(objT, Convert.ChangeType(wsRow[rowNum, position + 1].Value, propertyInfo.PropertyType));
}
}
retList.Add(objT);
}
}
return retList;
}
//IMPLEMENTATION DONE BY PLACING Code IT IN SEPARATE Helpers.CS file and
//Consuming it in this manner
List<CustomerExcelModel> records =
Helpers.GetClassFromExcel<CustomerExcelModel>(filelocation, 1, 1);
Thanks a lot to the user who Submitted code and Andreas for suggestion
Here are the Following changes done, i am new to generics so forgive and correct me for any mistakes please find modified code below it might help someone
Added Display Annotation entity model to map with the Excel Column
name so that Column Name with spaces can also be handled.
had issue "T objT " as it was outside of for loop and hence caused
same value repeatedly inserted into List fixed it by
instantiating inside loop i.e using "new T()"
Fixed Column out of range error by using "ws.Dimension.Columns" to get Column count , instead of ws.Cells.Count() as it caused out
range column error
for looping through row data added +1 to it ,as RowNum=1 was reading header name also so done minor change of "rowNum = fromRow + 1"
Here I am sharing how you can read the excel. You can modify it to store each date in datatables.
public void readXLS(string FilePath)
{
FileInfo existingFile = new FileInfo(FilePath);
using (ExcelPackage package = new ExcelPackage(existingFile))
{
//get the first worksheet in the workbook
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
int colCount = worksheet.Dimension.End.Column; //get Column Count
int rowCount = worksheet.Dimension.End.Row; //get row count
for (int row = 1; row <= rowCount; row++)
{
for (int col = 1; col <= colCount; col++)
{
//You can update code here to add each cell value to DataTable.
Console.WriteLine(" Row:" + row + " column:" + col + " Value:" + worksheet.Cells[row, col].Value.ToString().Trim());
}
}
}
}
Reff: http://sforsuresh.in/read-data-excel-sheet-insert-database-table-c/
Use below code if you want to read data of each worksheet from excel, as well if worksheet contain date format data for particular column.
public static DataSet ReadExcelFileToDataSet2(string filePath, bool isFirstRowHeader=true)
{
DataSet result = new DataSet();
Excel.ExcelPackage xlsPackage = new Excel.ExcelPackage(new FileInfo(filePath)); //using Excel = OfficeOpenXml; <--EPPLUS
Excel.ExcelWorkbook workBook = xlsPackage.Workbook;
try
{
for (int count = 1; count <= workBook.Worksheets.Count; count++)
{
Excel.ExcelWorksheet wsworkSheet = workBook.Worksheets[count];
if (wsworkSheet.Name.ToLower() == "sheetName")
{
wsworkSheet.Column(4).Style.Numberformat.Format = "MM-dd-yyyy"; // set column value to read as Date Type or numberformat
}
DataTable tbl = new DataTable();
// wsworkSheet.Dimension - (It will return cell dimesion like A1:N7 , means returning the worksheet dimesions.)
// wsworkSheet.Dimension.End.Address - (It will return right bottom cell like N7)
// wsworkSheet.Dimension.End.Columns - (It will return count from A1 to N7 like here 14)
foreach (var firstRowCell in wsworkSheet.Cells[1, 1, 1, wsworkSheet.Dimension.End.Column]) //.Cells[Row start, Column Start, Row end, Column End]
{
var colName = "";
colName = firstRowCell.Text;
tbl.Columns.Add(isFirstRowHeader ? colName : string.Format("Column {0}", firstRowCell.Start.Column)); //Geth the Column index (index starting with 1) from the left top.
}
var startRow = isFirstRowHeader ? 2 : 1;
for (int rowNum = startRow; rowNum <= wsworkSheet.Dimension.End.Row; rowNum++)
{
var wsRow = wsworkSheet.Cells[rowNum, 1, rowNum, wsworkSheet.Dimension.End.Column]; // wsworkSheet.Cells[Row start, Column Start, Row end, Column End]
DataRow row = tbl.Rows.Add();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
}
tbl.TableName = wsworkSheet.Name;
result.Tables.Add(tbl);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
}
return result;
}