Issue writing to spreadsheet using EPPlus - c#

I'm simply trying to edit a spreadsheet that has text already written into to change the text to be blank.
However it's not working. The method seems to do nothing.
My code is:
public static void ClearCells(string SpreadsheetFilePath)
{
var SpreadsheetPath = new FileInfo(SpreadsheetFilePath);
var package = new ExcelPackage(SpreadsheetPath);
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
ExcelWorksheet currentWorksheet = workBook.Worksheets.First();
currentWorksheet.SetValue(1, 1, "hello123");
}
}
}
There is no runtime error. It runs, completes and the spreadsheet is unchanged. I don't know why.

Just call package.Save(); after you are done editing your file.
var SpreadsheetPath = new FileInfo(#"C:\temp\abc.xlsx");
var package = new ExcelPackage(SpreadsheetPath);
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
ExcelWorksheet currentWorksheet = workBook.Worksheets.First();
currentWorksheet.SetValue(1, 1, "hello123");
}
}
package.Save(); // <========= MISSING IN YOUR CODE

Try something like this:
public static void ClearCells(string SpreadsheetFilePath)
{
var excelFile = new FileInfo(SpreadsheetFilePath);
var excelPack = ExcelPackage(excelFile);
var workSheet = excelPack.Workbook.Worksheets.Add("Content"); // New worksheet
workSheet.Cells[1, 1].Value = "hello123";
excelPack.Save();
}

How about using SetCellValue instead of SetValue?
public static void ClearCells(string SpreadsheetFilePath)
{
var SpreadsheetPath = new FileInfo(SpreadsheetFilePath);
var package = new ExcelPackage(SpreadsheetPath);
ExcelWorkbook workBook = package.Workbook;
if (workBook != null)
{
if (workBook.Worksheets.Count > 0)
{
ExcelWorksheet currentWorksheet = workBook.Worksheets.First();
currentWorksheet.SetCellValue(1, 1, "hello123");
}
}
}

Related

How to add multiple worksheets in workbook C#

I am trying to generate multiple worksheets for every student in my list but not sure how to achieve this,i can generate Excel document with one worksheet successfully but shows all students in one sheet,how can i generate a new sheet for every student?i tried achieving this with the code below thanks.
public FileContentResult GenerateStudentReport([FromForm] Student Students)
{
int count = 0;
Workbook workbook = new Workbook();
Worksheet worksheet;
foreach (var item in Students)
{
worksheet = workbook.Worksheets[count];
var dataSet = new DataSet();
// Add the new DataTable to the DataSet.
dataSet.Tables.Add(table);
row["studentid"] = Convert.ToString(item.id);
row["studentName"] = Convert.ToString(item.Name);
row["studentSurname"] = Convert.ToString(item.Surname);...
table.Rows.Add(row);
worksheet[count].Import(table, true, 0, 0);
worksheet[count]["A1:V1"].Font.Bold = true;
worksheet[count]["A1:V1"].ColumnWidth = 300;
worksheet[count]["A1:V1"].Style.NumberFormat = "0.00";
worksheet[count].Import(table, true, 0, 0);
count++;
}
byte[] docBytes = workbook.SaveDocument(DocumentFormat.Xlsx);
return File(docBytes, "application/vnd.ms-excel", $"ExportForecastReport_{DateTime.Now.ToString("HH-mm-ss yyyyy-dd-MM")}.xlsx"); // returns a FileStreamResult
}
error thrown while trying to generate second worksheet:{"Worksheet index should be positive and less than the number of worksheets. (Parameter 'index')"}
You should be able to do so with the following:
var newWorksheet = (Excel.Worksheet)this.Application.Worksheets.Add();
The idea is that you first add a new, empty Worksheet to the workbook and then work on it (similarly to what you would do manually in Excel)
You can use EPPlus Nuget package in your project, Then use below code.
public IActionResult EveryExcel([FromForm] Student users)
{
var stream = new MemoryStream();
ExcelPackage.LicenseContext = LicenseContext.NonCommercial;
using (var xlPackage = new ExcelPackage(stream))
{
int i = 1;
foreach(var user in users)
{
var worksheet = xlPackage.Workbook.Worksheets.Add($"StudentAll{i}");
var namedStyle = xlPackage.Workbook.Styles.CreateNamedStyle($"HyperLink{i}");
namedStyle.Style.Font.UnderLine = true;
namedStyle.Style.Font.Color.SetColor(Color.Blue);
const int startRow = 5;
var row = startRow;
worksheet.Cells["A1"].Value = "Sample";
using (var r = worksheet.Cells["A1:C1"])
{
r.Merge = true;
r.Style.Font.Color.SetColor(Color.White);
r.Style.HorizontalAlignment = OfficeOpenXml.Style.ExcelHorizontalAlignment.CenterContinuous;
r.Style.Fill.PatternType = OfficeOpenXml.Style.ExcelFillStyle.Solid;
r.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(23, 55, 93));
}
worksheet.Cells["A4"].Value = "ID";
worksheet.Cells["B4"].Value = "Name";
worksheet.Cells["C4"].Value = "Surname";
worksheet.Cells["A4:C4"].Style.Fill.PatternType = ExcelFillStyle.Solid;
worksheet.Cells["A4:C4"].Style.Fill.BackgroundColor.SetColor(Color.FromArgb(184, 204, 228));
worksheet.Cells["A4:C4"].Style.Font.Bold = true;
worksheet.Cells[row, 1].Value = user.Id;
worksheet.Cells[row, 2].Value = user.Name;
worksheet.Cells[row, 3].Value = user.Surname;
i++;
}
xlPackage.Save();
}
stream.Position = 0;
return File(stream, "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet", "students.xlsx");
}
Then it will generate a new sheet for every student

Disable Winform application cache

I developed winform application that read from excel and transform it to text files.
I used Microsoft.Office.Interop.Excel library in order to work with Excel.
Here is my code:
private Excel.Application excel = null;
private Excel.Sheets sheets = null;
private Excel.Workbook excelWorkbook = null;
private Excel.Workbooks excelWorkbooks = null;
private Excel._Worksheet worksheet = null;
private Excel.Range usedRange = null;
public ExcelFacade() { }
public ExcelFacade(string fileName)
{
excel = new Excel.Application();
excelWorkbooks = excel.Workbooks;
excelWorkbook = excelWorkbooks.Open(fileName, 0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
sheets = excelWorkbook.Sheets;
}
After I finished work with Excel I call next method (from here):
public void Dispose()
{
foreach (Microsoft.Office.Interop.Excel.Worksheet sheet in sheets)
{
while (Marshal.ReleaseComObject(sheet) != 0) { }
}
excelWorkbook.Close();
excelWorkbooks.Close();
excel.Quit();
var chromeDriverProcesses = Process.GetProcesses().
Where(pr => pr.ProcessName.ToLower().Contains("excel"));
foreach (var process in chromeDriverProcesses)
{
process.Kill();
}
//while (Marshal.ReleaseComObject(usedRange) != 0) { }
//while (Marshal.ReleaseComObject(worksheet) != 0) { }
while (Marshal.ReleaseComObject(sheets) != 0) { }
while (Marshal.ReleaseComObject(excelWorkbook) != 0) { }
while (Marshal.ReleaseComObject(excelWorkbooks) != 0) { }
//while (Marshal.ReleaseComObject(excel.Application) != 0)
//{ }
while (Marshal.ReleaseComObject(excel) != 0) { }
usedRange = null;
worksheet = null;
excelWorkbook = null;
excelWorkbooks = null;
sheets = null;
excel = null;
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
GC.WaitForPendingFinalizers();
}
}
However, if I change excel and rerun my application, the updated excel is not taken by application and it looks like it read from old excel. Such behavior is look like caching and I have no idea how to disable it.
The aforementioned is strengthened by the fact that if I change something in my code, e.g. white space, and rebuild the application, it works brilliant and take right Excel file.
Any suggestions?
As #vbnet3d said, using ClosedXML library solves all problems

EPPlus - How to use a template

I have recently discovered EPPlus (http://epplus.codeplex.com/).
I have an excel .xlsx file in my project with all the styled column headers.
I read on their site that you can use templates.
Does anyone know how or can provide code sample of how to use my template.xlsx file with EPPlus? I would like to be able to simply load my data into the rows without messing with the headings.
The solution I ended up going with:
using System.IO;
using System.Reflection;
using OfficeOpenXml;
//Create a stream of .xlsx file contained within my project using reflection
Stream stream = Assembly.GetExecutingAssembly().GetManifestResourceStream("EPPlusTest.templates.VendorTemplate.xlsx");
//EPPlusTest = Namespace/Project
//templates = folder
//VendorTemplate.xlsx = file
//ExcelPackage has a constructor that only requires a stream.
ExcelPackage pck = new OfficeOpenXml.ExcelPackage(stream);
After that you can use all the methods of ExcelPackage that you want on an .xlsx file loaded from a template.
To create a new package, you can provide a stream template:
// templateName = the name of .xlsx file
// result = stream to write the resulting xlsx to
using (var source = System.IO.File.OpenRead(templateName))
using (var excel = new OfficeOpenXml.ExcelPackage(result, source)) {
// Fill cells here
// Leave headers etc as is
excel.Save();
}
//This is my Implementation for EPPlus. // may be it helps.
class EPPlus
{
FileInfo newFile;
FileInfo templateFile;
DataSet _ds;
ExcelPackage xlPackage;
public string _ErrorMessage;
public EPPlus(string filePath, string templateFilePath)
{
newFile = new FileInfo(#filePath);
templateFile = new FileInfo(#templateFilePath);
_ds = GetDataTables(); /* DataTables */
_ErrorMessage = string.Empty;
CreateFileWithTemplate();
}
private bool CreateFileWithTemplate()
{
try
{
_ErrorMessage = string.Empty;
using (xlPackage = new ExcelPackage(newFile, templateFile))
{
int i = 1;
foreach (DataTable dt in _ds.Tables)
{
AddSheetWithTemplate(xlPackage, dt, i);
i++;
}
///* Set title, Author.. */
//xlPackage.Workbook.Properties.Title = "Title: Office Open XML Sample";
//xlPackage.Workbook.Properties.Author = "Author: Muhammad Mubashir.";
////xlPackage.Workbook.Properties.SetCustomPropertyValue("EmployeeID", "1147");
//xlPackage.Workbook.Properties.Comments = "Sample Record Details";
//xlPackage.Workbook.Properties.Company = "TRG Tech.";
///* Save */
xlPackage.Save();
}
return true;
}
catch (Exception ex)
{
_ErrorMessage = ex.Message.ToString();
return false;
}
}
/// <summary>
/// This AddSheet method generates a .xlsx Sheet with your provided Template file, //DataTable and SheetIndex.
/// </summary>
public static void AddSheetWithTemplate(ExcelPackage xlApp, DataTable dt, int SheetIndex)
{
string _SheetName = string.Format("Sheet{0}", SheetIndex.ToString());
ExcelWorksheet worksheet;
/* WorkSheet */
if (SheetIndex == 0)
{
worksheet = xlApp.Workbook.Worksheets[SheetIndex + 1]; // add a new worksheet to the empty workbook
}
else
{
worksheet = xlApp.Workbook.Worksheets[SheetIndex]; // add a new worksheet to the empty workbook
}
if (worksheet == null)
{
worksheet = xlApp.Workbook.Worksheets.Add(_SheetName); // add a new worksheet to the empty workbook
}
else
{
}
/* Load the datatable into the sheet, starting from cell A1. Print the column names on row 1 */
worksheet.Cells["A1"].LoadFromDataTable(dt, true);
}
private static void AddSheet(ExcelPackage xlApp, DataTable dt, int Index, string sheetName)
{
string _SheetName = string.Empty;
if (string.IsNullOrEmpty(sheetName) == true)
{
_SheetName = string.Format("Sheet{0}", Index.ToString());
}
else
{
_SheetName = sheetName;
}
/* WorkSheet */
ExcelWorksheet worksheet = xlApp.Workbook.Worksheets[_SheetName]; // add a new worksheet to the empty workbook
if (worksheet == null)
{
worksheet = xlApp.Workbook.Worksheets.Add(_SheetName); // add a new worksheet to the empty workbook
}
else
{
}
/* Load the datatable into the sheet, starting from cell A1. Print the column names on row 1 */
worksheet.Cells["A1"].LoadFromDataTable(dt, true);
int rowCount = dt.Rows.Count;
int colCount = dt.Columns.Count;
#region Set Column Type to Date using LINQ.
/*
IEnumerable<int> dateColumns = from DataColumn d in dt.Columns
where d.DataType == typeof(DateTime) || d.ColumnName.Contains("Date")
select d.Ordinal + 1;
foreach (int dc in dateColumns)
{
xlSheet.Cells[2, dc, rowCount + 1, dc].Style.Numberformat.Format = "dd/MM/yyyy";
}
*/
#endregion
#region Set Column Type to Date using LOOP.
/* Set Column Type to Date. */
for (int i = 0; i < dt.Columns.Count; i++)
{
if ((dt.Columns[i].DataType).FullName == "System.DateTime" && (dt.Columns[i].DataType).Name == "DateTime")
{
//worksheet.Cells[2,4] .Style.Numberformat.Format = "yyyy-mm-dd h:mm"; //OR "yyyy-mm-dd h:mm" if you want to include the time!
worksheet.Column(i + 1).Style.Numberformat.Format = "dd/MM/yyyy h:mm"; //OR "yyyy-mm-dd h:mm" if you want to include the time!
worksheet.Column(i + 1).Width = 25;
}
}
#endregion
//(from DataColumn d in dt.Columns select d.Ordinal + 1).ToList().ForEach(dc =>
//{
// //background color
// worksheet.Cells[1, 1, 1, dc].Style.Fill.PatternType = ExcelFillStyle.Solid;
// worksheet.Cells[1, 1, 1, dc].Style.Fill.BackgroundColor.SetColor(System.Drawing.Color.LightYellow);
// //border
// worksheet.Cells[1, dc, rowCount + 1, dc].Style.Border.Top.Style = ExcelBorderStyle.Thin;
// worksheet.Cells[1, dc, rowCount + 1, dc].Style.Border.Right.Style = ExcelBorderStyle.Thin;
// worksheet.Cells[1, dc, rowCount + 1, dc].Style.Border.Bottom.Style = ExcelBorderStyle.Thin;
// worksheet.Cells[1, dc, rowCount + 1, dc].Style.Border.Left.Style = ExcelBorderStyle.Thin;
// worksheet.Cells[1, dc, rowCount + 1, dc].Style.Border.Top.Color.SetColor(System.Drawing.Color.LightGray);
// worksheet.Cells[1, dc, rowCount + 1, dc].Style.Border.Right.Color.SetColor(System.Drawing.Color.LightGray);
// worksheet.Cells[1, dc, rowCount + 1, dc].Style.Border.Bottom.Color.SetColor(System.Drawing.Color.LightGray);
// worksheet.Cells[1, dc, rowCount + 1, dc].Style.Border.Left.Color.SetColor(System.Drawing.Color.LightGray);
//});
/* Format the header: Prepare the range for the column headers */
string cellRange = "A1:" + Convert.ToChar('A' + colCount - 1) + 1;
using (ExcelRange rng = worksheet.Cells[cellRange])
{
rng.Style.Font.Bold = true;
rng.Style.Fill.PatternType = ExcelFillStyle.Solid; //Set Pattern for the background to Solid
rng.Style.Fill.BackgroundColor.SetColor(Color.FromArgb(79, 129, 189)); //Set color to dark blue
rng.Style.Font.Color.SetColor(Color.White);
}
/* Header Footer */
worksheet.HeaderFooter.OddHeader.CenteredText = "Header: Tinned Goods Sales";
worksheet.HeaderFooter.OddFooter.RightAlignedText = string.Format("Footer: Page {0} of {1}", ExcelHeaderFooter.PageNumber, ExcelHeaderFooter.NumberOfPages); // add the page number to the footer plus the total number of pages
}
}// class End.
I use Vb.net, here is what I did:
VB
Imports OfficeOpenXml
Dim existingFile As New FileInfo("C:\OldFileLocation\File.xlsx")
Dim fNewFile As New FileInfo("C:\NewFileLocation\File.xlsx")
Using MyExcel As New ExcelPackage(existingFile)
Dim MyWorksheet As ExcelWorksheet = MyExcel.Workbook.Worksheets("ExistingSheetName")
MyWorksheet.Cells("A1").Value = "Hello"
'Add additional info here
MyExcel.SaveAs(fNewFile)
End Using
Posible C# (I did not test)
FileInfo existingFile = new FileInfo("C:\\OldFileLocation\\File.xlsx");
FileInfo fNewFile = new FileInfo("C:\\NewFileLocation\\File.xlsx");
using (ExcelPackage MyExcel = new ExcelPackage(existingFile)) {
ExcelWorksheet MyWorksheet = MyExcel.Workbook.Worksheets["ExistingSheetName"];
MyWorksheet.Cells["A1"].Value = "Hello";
//Add additional info here
MyExcel.SaveAs(fNewFile);
}
Response.Clear();
Response.ContentType = "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet";
Response.AddHeader("content-disposition", "attachment;filename=" + HttpUtility.UrlEncode("Logs.xlsx", System.Text.Encoding.UTF8));
using (ExcelPackage pck = new ExcelPackage())
{
ExcelWorksheet ws = pck.Workbook.Worksheets.Add("Logs");
ws.Cells["A1"].LoadFromDataTable(dt, true);
var ms = new System.IO.MemoryStream();
pck.SaveAs(ms);
ms.WriteTo(Response.OutputStream);
}

How do I auto size columns through the Excel interop objects?

Below is the code I'm using to load the data into an Excel worksheet, but I'm look to auto size the column after the data is loaded. Does anyone know the best way to auto size the columns?
using Microsoft.Office.Interop;
public class ExportReport
{
public void Export()
{
Excel.Application excelApp = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbook wb;
Excel.Worksheet ws;
Excel.Range aRange;
object m = Type.Missing;
string[,] data;
string errorMessage = string.Empty;
try
{
if (excelApp == null)
throw new Exception("EXCEL could not be started.");
// Create the workbook and worksheet.
wb = excelApp.Workbooks.Add(Office.Excel.XlWBATemplate.xlWBATWorksheet);
ws = (Office.Excel.Worksheet)wb.Worksheets[1];
if (ws == null)
throw new Exception("Could not create worksheet.");
// Set the range to fill.
aRange = ws.get_Range("A1", "E100");
if (aRange == null)
throw new Exception("Could not get a range.");
// Load the column headers.
data = new string[100, 5];
data[0, 0] = "Column 1";
data[0, 1] = "Column 2";
data[0, 2] = "Column 3";
data[0, 3] = "Column 4";
data[0, 4] = "Column 5";
// Load the data.
for (int row = 1; row < 100; row++)
{
for (int col = 0; col < 5; col++)
{
data[row, col] = "STUFF";
}
}
// Save all data to the worksheet.
aRange.set_Value(m, data);
// Atuo size columns
// TODO: Add Code to auto size columns.
// Save the file.
wb.SaveAs("C:\Test.xls", Office.Excel.XlFileFormat.xlExcel8, m, m, m, m, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlNoChange, m, m, m, m, m);
// Close the file.
wb.Close(false, false, m);
}
catch (Exception) { }
finally
{
// Close the connection.
cmd.Close();
// Close Excel.
excelApp.Quit();
}
}
}
Add this at your TODO point:
aRange.Columns.AutoFit();
This might be too late but if you add
worksheet.Columns.AutoFit();
or
worksheet.Rows.AutoFit();
it also works.
Also there is
aRange.EntireColumn.AutoFit();
See What is the difference between Range.Columns and Range.EntireColumn.
This method opens already created excel file, Autofit all columns of all sheets based on 3rd Row. As you can see Range is selected From "A3 to K3" in excel.
public static void AutoFitExcelSheets()
{
Microsoft.Office.Interop.Excel.Application _excel = null;
Microsoft.Office.Interop.Excel.Workbook excelWorkbook = null;
try
{
string ExcelPath = ApplicationData.PATH_EXCEL_FILE;
_excel = new Microsoft.Office.Interop.Excel.Application();
_excel.Visible = false;
object readOnly = false;
object isVisible = true;
object missing = System.Reflection.Missing.Value;
excelWorkbook = _excel.Workbooks.Open(ExcelPath,
0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "",
true, false, 0, true, false, false);
Microsoft.Office.Interop.Excel.Sheets excelSheets = excelWorkbook.Worksheets;
foreach (Microsoft.Office.Interop.Excel.Worksheet currentSheet in excelSheets)
{
string Name = currentSheet.Name;
Microsoft.Office.Interop.Excel.Worksheet excelWorksheet = (Microsoft.Office.Interop.Excel.Worksheet)excelSheets.get_Item(Name);
Microsoft.Office.Interop.Excel.Range excelCells =
(Microsoft.Office.Interop.Excel.Range)excelWorksheet.get_Range("A3", "K3");
excelCells.Columns.AutoFit();
}
}
catch (Exception ex)
{
ProjectLog.AddError("EXCEL ERROR: Can not AutoFit: " + ex.Message);
}
finally
{
excelWorkbook.Close(true, Type.Missing, Type.Missing);
GC.Collect();
GC.WaitForPendingFinalizers();
releaseObject(excelWorkbook);
releaseObject(_excel);
}
}
Have a look at this article, it's not an exact match to your problem, but suits it:
Craig Murphy - Excel – wordwrap row autosize issue

c# (WinForms-App) export DataSet to Excel

I need a solution to export a dataset to an excel file without any asp code (HttpResonpsne...) but i did not find a good example to do this...
Best thanks in advance
I've created a class that exports a DataGridView or DataTable to an Excel file. You can probably change it a bit to make it use your DataSet instead (iterating through the DataTables in it). It also does some basic formatting which you could also extend.
To use it, simply call ExcelExport, and specify a filename and whether to open the file automatically or not after exporting. I also could have made them extension methods, but I didn't. Feel free to.
Note that Excel files can be saved as a glorified XML document and this makes use of that.
EDIT: This used to use a vanilla StreamWriter, but as pointed out, things would not be escaped correctly in many cases. Now it uses a XmlWriter, which will do the escaping for you.
The ExcelWriter class wraps an XmlWriter. I haven't bothered, but you might want to do a bit more error checking to make sure you can't write cell data before starting a row, and such. The code is below.
public class ExcelWriter : IDisposable
{
private XmlWriter _writer;
public enum CellStyle { General, Number, Currency, DateTime, ShortDate };
public void WriteStartDocument()
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteProcessingInstruction("mso-application", "progid=\"Excel.Sheet\"");
_writer.WriteStartElement("ss", "Workbook", "urn:schemas-microsoft-com:office:spreadsheet");
WriteExcelStyles();
}
public void WriteEndDocument()
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteEndElement();
}
private void WriteExcelStyleElement(CellStyle style)
{
_writer.WriteStartElement("Style", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("ID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
_writer.WriteEndElement();
}
private void WriteExcelStyleElement(CellStyle style, string NumberFormat)
{
_writer.WriteStartElement("Style", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("ID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
_writer.WriteStartElement("NumberFormat", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("Format", "urn:schemas-microsoft-com:office:spreadsheet", NumberFormat);
_writer.WriteEndElement();
_writer.WriteEndElement();
}
private void WriteExcelStyles()
{
_writer.WriteStartElement("Styles", "urn:schemas-microsoft-com:office:spreadsheet");
WriteExcelStyleElement(CellStyle.General);
WriteExcelStyleElement(CellStyle.Number, "General Number");
WriteExcelStyleElement(CellStyle.DateTime, "General Date");
WriteExcelStyleElement(CellStyle.Currency, "Currency");
WriteExcelStyleElement(CellStyle.ShortDate, "Short Date");
_writer.WriteEndElement();
}
public void WriteStartWorksheet(string name)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteStartElement("Worksheet", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("Name", "urn:schemas-microsoft-com:office:spreadsheet", name);
_writer.WriteStartElement("Table", "urn:schemas-microsoft-com:office:spreadsheet");
}
public void WriteEndWorksheet()
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteEndElement();
_writer.WriteEndElement();
}
public ExcelWriter(string outputFileName)
{
XmlWriterSettings settings = new XmlWriterSettings();
settings.Indent = true;
_writer = XmlWriter.Create(outputFileName, settings);
}
public void Close()
{
if (_writer == null) throw new InvalidOperationException("Already closed.");
_writer.Close();
_writer = null;
}
public void WriteExcelColumnDefinition(int columnWidth)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteStartElement("Column", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteStartAttribute("Width", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteValue(columnWidth);
_writer.WriteEndAttribute();
_writer.WriteEndElement();
}
public void WriteExcelUnstyledCell(string value)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteStartElement("Cell", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteStartElement("Data", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "String");
_writer.WriteValue(value);
_writer.WriteEndElement();
_writer.WriteEndElement();
}
public void WriteStartRow()
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteStartElement("Row", "urn:schemas-microsoft-com:office:spreadsheet");
}
public void WriteEndRow()
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteEndElement();
}
public void WriteExcelStyledCell(object value, CellStyle style)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
_writer.WriteStartElement("Cell", "urn:schemas-microsoft-com:office:spreadsheet");
_writer.WriteAttributeString("StyleID", "urn:schemas-microsoft-com:office:spreadsheet", style.ToString());
_writer.WriteStartElement("Data", "urn:schemas-microsoft-com:office:spreadsheet");
switch (style)
{
case CellStyle.General:
_writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "String");
break;
case CellStyle.Number:
case CellStyle.Currency:
_writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "Number");
break;
case CellStyle.ShortDate:
case CellStyle.DateTime:
_writer.WriteAttributeString("Type", "urn:schemas-microsoft-com:office:spreadsheet", "DateTime");
break;
}
_writer.WriteValue(value);
// tag += String.Format("{1}\"><ss:Data ss:Type=\"DateTime\">{0:yyyy\\-MM\\-dd\\THH\\:mm\\:ss\\.fff}</ss:Data>", value,
_writer.WriteEndElement();
_writer.WriteEndElement();
}
public void WriteExcelAutoStyledCell(object value)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
//write the <ss:Cell> and <ss:Data> tags for something
if (value is Int16 || value is Int32 || value is Int64 || value is SByte ||
value is UInt16 || value is UInt32 || value is UInt64 || value is Byte)
{
WriteExcelStyledCell(value, CellStyle.Number);
}
else if (value is Single || value is Double || value is Decimal) //we'll assume it's a currency
{
WriteExcelStyledCell(value, CellStyle.Currency);
}
else if (value is DateTime)
{
//check if there's no time information and use the appropriate style
WriteExcelStyledCell(value, ((DateTime)value).TimeOfDay.CompareTo(new TimeSpan(0, 0, 0, 0, 0)) == 0 ? CellStyle.ShortDate : CellStyle.DateTime);
}
else
{
WriteExcelStyledCell(value, CellStyle.General);
}
}
#region IDisposable Members
public void Dispose()
{
if (_writer == null)
return;
_writer.Close();
_writer = null;
}
#endregion
}
Then you can export your DataTable using the following:
public static void ExcelExport(DataTable data, String fileName, bool openAfter)
{
//export a DataTable to Excel
DialogResult retry = DialogResult.Retry;
while (retry == DialogResult.Retry)
{
try
{
using (ExcelWriter writer = new ExcelWriter(fileName))
{
writer.WriteStartDocument();
// Write the worksheet contents
writer.WriteStartWorksheet("Sheet1");
//Write header row
writer.WriteStartRow();
foreach (DataColumn col in data.Columns)
writer.WriteExcelUnstyledCell(col.Caption);
writer.WriteEndRow();
//write data
foreach (DataRow row in data.Rows)
{
writer.WriteStartRow();
foreach (object o in row.ItemArray)
{
writer.WriteExcelAutoStyledCell(o);
}
writer.WriteEndRow();
}
// Close up the document
writer.WriteEndWorksheet();
writer.WriteEndDocument();
writer.Close();
if (openAfter)
OpenFile(fileName);
retry = DialogResult.Cancel;
}
}
catch (Exception myException)
{
retry = MessageBox.Show(myException.Message, "Excel Export", MessageBoxButtons.RetryCancel, MessageBoxIcon.Asterisk);
}
}
}
The following site demonstrates how to export a DataSet (or DataTable or List<>) into a "genuine" Excel 2007 .xlsx file.
It uses the OpenXML libraries, so you don't need to have Excel installed on your server.
C# ExportToExcel library
All of the source code is provided, free of charge, along with instructions using it with ASP.NET, ASP.NET Core 2+ or regular C#.
It's very easy to add to your own applications, you just need to call one function, passing in an Excel filename, and your data source:
DataSet ds = CreateSampleData();
string excelFilename = "C:\\Sample.xlsx";
CreateExcelFile.CreateExcelDocument(ds, excelFilename);
Hope this helps.
Creating excel files in .NET applications is quite common and similar questions have been asked several times before. For instance here and here. The last question asks about reading excel files, but most suggested solutions should work both ways.
This was a post with a really helpful top answer, but I found it was lacking because there was no simple way to import the XML file back into a datatable. I ended up having to write my own, and thought I would share it here in case anyone else was in the same boat (google was exceptionally unhelpful in that regard):
public static DataTable ImportExcelXML(string Filename)
{
//create a new dataset to load in the XML file
DataSet DS = new DataSet();
//Read the XML file into the dataset
DS.ReadXml(Filename);
//Create a new datatable to store the raw Data
DataTable Raw = new DataTable();
//assign the raw data from the file to the datatable
Raw = DS.Tables["Data"];
//count the number of columns in the XML file
int ColumnNumber = Raw.Columns.Count;
//create a datatable to store formatted Import Data
DataTable ImportData = new DataTable();
//create a string list to store the cell data of each row
List<string> RowData = new List<string>();
//loop through each row in the raw data table
for (int Counter = 0; Counter < Raw.Rows.Count; Counter++)
{
//if the data in the row is a colum header
if (Counter < ColumnNumber)
{
//add the column name to our formatted datatable
ImportData.Columns.Add(Raw.Rows[Counter].ItemArray.GetValue(1).ToString());
}
else
{
//if the row # (1 row = 1 cell from the excel file) from the raw datatable is divisable evenly by the number of columns in the formated import datatable AND this is not the 1st row of the raw table data after the headers
if ((Counter % ColumnNumber == 0) && (Counter != ColumnNumber))
{
//add the row we just built to the formatted import datatable
ImportData.Rows.Add(GenerateRow(ImportData, RowData));
//clear rowdata list in preperation for the next row
RowData.Clear();
}
//add the current cell data value from the raw datatable to the string list of cell values for the next row to be added to the formatted input datatable
RowData.Add(Raw.Rows[Counter].ItemArray.GetValue(1).ToString());
}
}
//add the final row
ImportData.Rows.Add(GenerateRow(ImportData, RowData));
return ImportData;
}
public static DataRow GenerateRow(DataTable ImportData, List<string> RowData)
{
//create a counter to keep track of the column position during row composition
int ColumnPosition = 0;
//make a new datarow based on the schema of the formated import datatable
DataRow NewRow = ImportData.NewRow();
//for each string cell value collected for the RowData list for this row
foreach (string CellData in RowData)
{
//add the cell value to the new datarow
NewRow[ImportData.Columns[ColumnPosition].ColumnName] = CellData;
//incriment column position in the new row
ColumnPosition++;
}
//return the generated row
return NewRow;
}
the code have problem with null values.
public void WriteExcelAutoStyledCell(object value)
{
//solve null values
if (value is DBNull) return;
I would have added this to the comments but I am new to stack so I am unable to comment. Using lc.'s solution I added another function that tests the strings characters for invalid XML characters. When I was exporting to excel on occasion there were characters that were found that were causing the export to fail.
You will need to modify one of the functions that is in lc's code.
public void WriteExcelAutoStyledCell(object value)
{
if (_writer == null) throw new InvalidOperationException("Cannot write after closing.");
string newValue = string.Empty;
try
{
//write the <ss:Cell> and <ss:Data> tags for something
if (value is Int16 || value is Int32 || value is Int64 || value is SByte ||
value is UInt16 || value is UInt32 || value is UInt64 || value is Byte)
{
WriteExcelStyledCell(value, CellStyle.Number);
}
else if (value is Single || value is Double || value is Decimal) //we'll assume it's a currency
{
WriteExcelStyledCell(value, CellStyle.Currency);
}
else if (value is DateTime)
{
//check if there's no time information and use the appropriate style
WriteExcelStyledCell(value, ((DateTime)value).TimeOfDay.CompareTo(new TimeSpan(0, 0, 0, 0, 0)) == 0 ? CellStyle.ShortDate : CellStyle.DateTime);
}
else
{
newValue = CheckXmlCompatibleValues(value.ToString()).ToString();
WriteExcelStyledCell(newValue, CellStyle.General);
}
}
catch (Exception thisException)
{
throw new InvalidOperationException(thisException.Message.ToString());
}
}
And add this function to 'ExcelWriter' class
public string CheckXmlCompatibleValues(string value)
{
string newValue = string.Empty;
bool found = false;
foreach (char c in value)
{
if (XmlConvert.IsXmlChar(c))
newValue += c.ToString();
else
found = true;
}
return newValue.ToString();
}
lc. Thanks for the code!
using XL = Microsoft.Office.Interop.Excel;
using System.Reflection;
public static void Datasource(DataTable dt)
{
XL.Application oXL;
XL._Workbook oWB;
XL._Worksheet oSheet;
XL.Range oRng;
try
{
oXL = new XL.Application();
Application.DoEvents();
oXL.Visible = false;
//Get a new workbook.
oWB = (XL._Workbook)(oXL.Workbooks.Add(Missing.Value));
oSheet = (XL._Worksheet)oWB.ActiveSheet;
//System.Data.DataTable dtGridData=ds.Tables[0];
int iRow = 2;
if (dt.Rows.Count > 0)
{
for (int j = 0; j < dt.Columns.Count; j++)
{
oSheet.Cells[1, j + 1] = dt.Columns[j].ColumnName;
}
// For each row, print the values of each column.
for (int rowNo = 0; rowNo < dt.Rows.Count; rowNo++)
{
for (int colNo = 0; colNo < dt.Columns.Count; colNo++)
{
oSheet.Cells[iRow, colNo + 1] = dt.Rows[rowNo][colNo].ToString();
}
iRow++;
}
iRow++;
}
oRng = oSheet.get_Range("A1", "IV1");
oRng.EntireColumn.AutoFit();
oXL.Visible = true;
}
catch (Exception theException)
{
throw theException;
}
finally
{
oXL = null;
oWB = null;
oSheet = null;
oRng = null;
}
}
Import from Excel to datatable:
DataTable dtTable = new DataTable();
DataColumn col = new DataColumn("Rfid");
dtTable.Columns.Add(col);
DataRow drRow;
Microsoft.Office.Interop.Excel.Application ExcelObj =
new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook theWorkbook =
ExcelObj.Workbooks.Open(txt_FilePath.Text, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
Microsoft.Office.Interop.Excel.Sheets sheets = theWorkbook.Worksheets;
try
{
for (int sht = 1; sht <= sheets.Count; sht++)
{
Microsoft.Office.Interop.Excel.Worksheet worksheet =
(Microsoft.Office.Interop.Excel.Worksheet)sheets.get_Item(sht);
for (int i = 2; i <= worksheet.UsedRange.Rows.Count; i++)
{
Microsoft.Office.Interop.Excel.Range range = worksheet.get_Range("A" + i.ToString(), "B" + i.ToString());
System.Array myvalues = (System.Array)range.Cells.Value2;
String name = Convert.ToString(myvalues.GetValue(1, 1));
if (string.IsNullOrEmpty(name) == false)
{
drRow = dtTable.NewRow();
drRow["Rfid"] = name;
dtTable.Rows.Add(drRow);
}
}
Marshal.ReleaseComObject(worksheet);
worksheet = null;
}
return dtTable;
}
catch
{
throw;
}
finally
{
// Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(theWorkbook);
Marshal.ReleaseComObject(ExcelObj);
//worksheet = null;
sheets = null;
theWorkbook = null;
ExcelObj = null;
}
Microsoft has a built in solution for Importing/Exporting Excel files. It's not the most straightforward library but it generally works better than the others listed above.
The library required to do this is included in Office and can be found under the list of Framework assemblies at Microsoft.Office.Interop.Excel.
Here is some example code:
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application app = new Excel.Application();
//Open existing workbook
//Excel.Workbook workbook = xlApp.Workbooks.Open(fileName);
//Create new workbook
Excel.Workbook workbook = app.Workbooks.Add();
Excel.Worksheet worksheet = workbook.ActiveSheet;
worksheet.Cells[1,1] = "Hello world!"; // Indexes start at 1, because Excel
workbook.SaveAs("C:\\MyWorkbook.xlsx");
workbook.Close();
app.Quit();

Categories

Resources