Error while exporting datatable to Excel - c#

I am using below code to export excel using Microsoft.Office.Interop.Excel. [Ms office 2003].
I need to export around 150000 rows can have maximum 300 columns.
but getting error on Get_Range. [ Working fine for 50000 rows and 40 columns]
public static void ExportToExcel(DataTable dt, string outputPath)
{
try
{
// Create the Excel Application object
ApplicationClass excelApp = new ApplicationClass();
// Create a new Excel Workbook
Workbook excelWorkbook = excelApp.Workbooks.Add(Type.Missing);
int sheetIndex = 0;
// Copy each DataTable
// Copy the DataTable to an object array
object[,] rawData = new object[dt.Rows.Count + 1, dt.Columns.Count];
// Copy the column names to the first row of the object array
for (int col = 0; col < dt.Columns.Count; col++)
{
rawData[0, col] = dt.Columns[col].ColumnName;
}
// Copy the values to the object array
for (int col = 0; col < dt.Columns.Count; col++)
{
for (int row = 0; row < dt.Rows.Count; row++)
{
rawData[row + 1, col] = dt.Rows[row].ItemArray[col];
}
}
// Calculate the final column letter
string finalColLetter = string.Empty;
string colCharset = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
int colCharsetLen = colCharset.Length;
if (dt.Columns.Count > colCharsetLen)
{
finalColLetter = colCharset.Substring(
(dt.Columns.Count - 1) / colCharsetLen - 1, 1);
}
finalColLetter += colCharset.Substring(
(dt.Columns.Count - 1) % colCharsetLen, 1);
// Create a new Sheet
Worksheet excelSheet = (Worksheet)excelWorkbook.Sheets.Add(
excelWorkbook.Sheets.get_Item(++sheetIndex),
Type.Missing, 1, XlSheetType.xlWorksheet);
excelSheet.Name = "data";
// Fast data export to Excel
string excelRange = string.Format("A1:{0}{1}",
finalColLetter, dt.Rows.Count + 1);
//excelSheet.get_Range(
excelSheet.get_Range(excelRange, Type.Missing).Value2 = rawData;
// Mark the first row as BOLD
((Range)excelSheet.Rows[1, Type.Missing]).Font.Bold = true;
// Save and Close the Workbook
excelWorkbook.SaveAs("C:\\Dashsrv\\data.Xls", XlFileFormat.xlWorkbookNormal, Type.Missing,
Type.Missing, Type.Missing, Type.Missing, XlSaveAsAccessMode.xlExclusive,
Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
excelWorkbook.Close(true, Type.Missing, Type.Missing);
excelWorkbook = null;
// Release the Application object
excelApp.Quit();
excelApp = null;
// Collect the unreferenced objects
GC.Collect();
GC.WaitForPendingFinalizers();
MessageBox.Show("File created at");
}
catch(Exception ex)
{
MessageBox.Show(ex.Message);
}
}
Getting error on below line of code
[{"Exception from HRESULT: 0x800A03EC"}]
excelSheet.get_Range(excelRange, Type.Missing).Value2 = rawData;
IS Get_Range() has some limitation for rows/Columns?
As I know for MS Office 2003 column's limit is 256, not sure about rows limt.
Thanks

Excel 2003 can have a maximum of 65536 rows in a single worksheet (specification)
Excel 2007 and newer can have 1048576 rows (specification: Excel 2007, Excel 2010 and Excel 2013)

Excel 2003 row limit is 65,536 - http://support.microsoft.com/kb/120596

Related

C# Open new Excel Workbook and Add Data

From a console application using C# I am trying to open a new Excel workbook and add data to it. I can open a new workbook fine, but I am running into issues adding data to the workbook because my range object is null, and I can't seem to hook into the excel workbook that was just opened. I tried a variation of ActiveWorkbook, Sheets[1] and a couple of others and I can't seem to figure it out
using Microsoft.Office.Interop.Excel;
using System.Reflection;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Application xl = null;
_Workbook wb = null;
// Option 1
xl = new Application();
xl.Visible = true;
wb = (_Workbook)(xl.Workbooks.Add(XlWBATemplate.xlWBATWorksheet));
Worksheet sheet = xl.ActiveWorkbook.ActiveSheet;
Range cell = sheet.Cells[1, 1];
//ERROR on cell.Value("Test");
cell.Value("Test");
}
}
}
This code may be help you.
using (SaveFileDialog sfd = new SaveFileDialog() { Filter = "Excel Workbook|*.xls" })
{
if (sfd.ShowDialog() == DialogResult.OK)
{
// creating Excel Application
Microsoft.Office.Interop.Excel._Application app = new Microsoft.Office.Interop.Excel.Application();
// creating new WorkBook within Excel application
Microsoft.Office.Interop.Excel._Workbook workbook = app.Workbooks.Add(Type.Missing);
// creating new Excelsheet in workbook
Microsoft.Office.Interop.Excel._Worksheet worksheet = null;
// see the excel sheet behind the program
app.Visible = true;
// get the reference of first sheet. By default its name is Sheet1.
// store its reference to worksheet
worksheet = workbook.Sheets["Sheet1"];
worksheet = workbook.ActiveSheet;
// changing the name of active sheet
worksheet.Name = "Exported from gridview";
// storing header part in Excel
for (int i = 1; i < DGView.Columns.Count + 1; i++)
{
worksheet.Cells[1, i] = DGView.Columns[i - 1].HeaderText;
}
// storing Each row and column value to excel sheet
for (int i = 0; i < DGView.Rows.Count - 1; i++)
{
for (int j = 0; j < DGView.Columns.Count; j++)
{
worksheet.Cells[i + 2, j + 1] = DGView.Rows[i].Cells[j].Value.ToString();
}
}
// save the application
workbook.SaveAs(sfd.FileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
// Exit from the application
app.Quit();
}
}
I used this code in my work for saving datagridview as excel sheet and it has been worked well.

C# Excel only allow edit for specific row

I'm generating an excel file in C# and excel file is format is as follows.
And Columns From C1 will be dynamic since there can be several dates.
And what I need to do is only allow editing for rows with Ctype
YYY
Is there any way to identify rows with Ctype = YYY
The code I use to generate excel is as follows
public string ExcelGenerator()
{
DataTable dt = GetDataTable();
var fileName = "ExcelFile";
var excelApp = new Application();
var workbooks = excelApp.Workbooks;
var excelWorkBook = workbooks.Add(XlWBATemplate.xlWBATWorksheet);
var sheets = excelWorkBook.Sheets;
var excelWorkSheet = sheets[1];
excelWorkSheet.Name = "ExcelFile";
int iCol = 1;
// Add column headings...
foreach (DataColumn c in dt.Columns)
{
excelWorkSheet.Cells[1, iCol] = c.ColumnName; ;
((Range)excelWorkSheet.Cells[1, iCol]).Interior.Color = ColorTranslator.ToOle(Color.DarkGray);
iCol++;
}
// for each row of data...
for (int j = 0; j < dt.Rows.Count; j++)
{
for (int k = 0; k < dt.Columns.Count; k++)
{
excelWorkSheet.Cells[j + 2, k + 1] = dt.Rows[j].ItemArray[k].ToString();
}
}
string fullpath = Path.Combine(excelPath, fileName);
if (File.Exists(fullpath))
{
try
{
File.Delete(fullpath);
}
catch (IOException e)
{
Console.Write(e.Message);
}
}
excelApp.DisplayAlerts = false;
excelWorkBook.SaveAs(fullpath, Microsoft.Office.Interop.Excel.XlFileFormat.xlWorkbookDefault, Type.Missing, Type.Missing, true, false, XlSaveAsAccessMode.xlNoChange, XlSaveConflictResolution.xlLocalSessionChanges, Type.Missing, Type.Missing);
excelWorkBook.Close(false, Type.Missing, Type.Missing);
excelApp.Quit();
Marshal.ReleaseComObject(workbooks);
Marshal.ReleaseComObject(excelWorkSheet);
Marshal.ReleaseComObject(sheets);
Marshal.ReleaseComObject(excelWorkBook);
Marshal.ReleaseComObject(excelApp);
excelWorkSheet = null;
excelWorkBook = null;
excelApp = null;
workbooks = null;
GC.WaitForPendingFinalizers();
GC.Collect();
return fileName;
}
Excel.Office.Interop don't allow range unprotection by programmatically.
For more information, you may visit this website.
https://msdn.microsoft.com/en-us/library/dkcs53f3.aspx
But if you use EPPlus library, you can do like Excel users.
if you allow selective editable column, excel requires sheet protection = true and some unprotected range.
(using EPPlus)
excelWorkSheet.Protection.IsProtected = true;
excelWorkSheet.ProtectedRanges.Add("editable", new ExcelAddress("B"));

C# Interop Save to excel from datagridview without creating new file

I want to make changes to an existing file named "Original" in the directory "C:\Users\Twiga\Documents\VisualStudio2010\Projects\MarkSheetSystem\Original.xls".
Currently, I am only able to save the data that I have exported from my datagridview1 to a new file but that is not my intention.
Below is the code:
private void btnexcel_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel._Application excel = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel._Workbook workbook = excel.Workbooks.Add(Type.Missing);
Microsoft.Office.Interop.Excel._Worksheet worksheet = null;
try
{
worksheet = workbook.ActiveSheet;
worksheet.Name = "Marksheet 1";
worksheet.Cells[12, 1] = dataGridView1.Rows[0].Cells[0].Value.ToString();
int cellRowIndex = 10;
int cellColumnIndex = 1;
//Loop through each row and read value from each column.
for (int i = 0; i < dataGridView1.Rows.Count; i++)
{
for (int j = 1; j < dataGridView1.Columns.Count - 1; j++)
{
// Excel index starts from 1,1. As first Row would have the Column headers, adding a condition check.
if (cellRowIndex == 0)
{
worksheet.Cells[cellRowIndex, cellColumnIndex] = dataGridView1.Columns[j].HeaderText;
}
else
{
worksheet.Cells[cellRowIndex, cellColumnIndex] = dataGridView1.Rows[i].Cells[j].Value.ToString();
}
cellColumnIndex++;
}
cellColumnIndex = 1;
cellRowIndex++;
}
//Getting the location and file name of the excel to save from user.
SaveFileDialog saveDialog = new SaveFileDialog();
saveDialog.Filter = "Excel files (*.xlsx)|*.xlsx|All files (*.*)|*.*";
saveDialog.FilterIndex = 2;
if (saveDialog.ShowDialog() == System.Windows.Forms.DialogResult.OK)
{
workbook.SaveAs(saveDialog.FileName);
MessageBox.Show("The marksheet has been saved successfully!");
}
}
catch (System.Exception ex)
{
MessageBox.Show(ex.Message);
}
finally
{
excel.Quit();
workbook = null;
excel = null;
}
}
Pertinent to your task, it would be better to export data to Excel Workbook from the DataGridView underlying DataTable (e.g. DataTable _dt = (DataTable)(datagridview1.DataSource)) as shown in the following C# sample code snippet:
/// <summary>
/// export DataTable to Excel (C#)
/// </summary>
internal static void Export2Excel(DataTable dataTable)
{
object misValue = System.Reflection.Missing.Value;
Microsoft.Office.Interop.Excel.Application _appExcel = null;
Microsoft.Office.Interop.Excel.Workbook _excelWorkbook = null;
Microsoft.Office.Interop.Excel.Worksheet _excelWorksheet = null;
try
{
// excel app object
_appExcel = new Microsoft.Office.Interop.Excel.Application();
// excel workbook object added
// can be replaced with _appExcel.Workbooks.Open(...)
_excelWorkbook = _appExcel.Workbooks.Add(misValue);
_excelWorksheet = _appExcel.ActiveWorkbook.ActiveSheet as Microsoft.Office.Interop.Excel.Worksheet;
// column names row (range obj)
Microsoft.Office.Interop.Excel.Range _columnsNameRange;
_columnsNameRange = _excelWorksheet.get_Range("A1", misValue).get_Resize(1, dataTable.Columns.Count);
// column names array to be assigned to _columnNameRange
string[] _arrColumnNames = new string[dataTable.Columns.Count];
for (int i = 0; i < dataTable.Columns.Count; i++)
{
// array of column names
_arrColumnNames[i] = dataTable.Columns[i].ColumnName;
}
// assign array to column headers range, make 'em bold
_columnsNameRange.set_Value(misValue, _arrColumnNames);
_columnsNameRange.Font.Bold = true;
// populate data content row by row
for (int Idx = 0; Idx < dataTable.Rows.Count; Idx++)
{
_excelWorksheet.Range["A2"].Offset[Idx].Resize[1, dataTable.Columns.Count].Value =
dataTable.Rows[Idx].ItemArray;
}
// Autofit all Columns in the range
_columnsNameRange.Columns.EntireColumn.AutoFit();
}
catch { throw; }
}
This will significantly improve the performance by exporting the entire data row at once instead of doing it cell-by-cell.
The only changes you have to make is to replace the line that adds new Workbook:
_excelWorkbook = _appExcel.Workbooks.Add(misValue);
with another one, opening the existing Excel File (e.g. "ExcelFilePath"), like:
_excelWorkbook = _appExcel.Workbooks.Open("ExcelFilePath",
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);
Hope this may help.

Export to Excel holding file open, and not exporting first datagrid

I am trying to export 2 datagridviews to excel but it is missing the last line of data for both of the sets of data grid views, I have checked the code and I cant see what I have done wrong? Also it is creating a temporary file when exporting and then locking the file and not exiting gracefully and only a reboot allows you to delete the file? Any help would be great code is below. For example if i save as test.xlsx I get 2 files ~$test.xlsx and test.xlsx and both both files are locked.
private void exprtbtn_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel._Application app = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel._Workbook workbook = app.Workbooks.Add(Type.Missing);
try
{
// creating new Excelsheet in workbook
Microsoft.Office.Interop.Excel._Worksheet worksheet1 = null;
Microsoft.Office.Interop.Excel._Worksheet worksheet2 = null;
// get the reference of first sheet. By default its name is Sheet1.
// store its reference to worksheet
worksheet1 = workbook.Sheets["Sheet1"];
worksheet1 = workbook.ActiveSheet;
// changing the name of active sheet
worksheet1.Name = "Switch Totals";
// storing header part in Excel
for (int i = 1; i < switchtotalgrd.Columns.Count + 1; i++)
{
worksheet1.Cells[1, i] = switchtotalgrd.Columns[i - 1].HeaderText;
}
// storing Each row and column value to excel sheet
for (int i = 0; i < switchtotalgrd.Rows.Count - 1; i++)
{
for (int j = 0; j < switchtotalgrd.Columns.Count; j++)
{
worksheet1.Cells[i + 2, j + 1] = switchtotalgrd.Rows[i].Cells[j].Value.ToString();
}
}
// Adding second worksheet
int count = workbook.Worksheets.Count;
Excel.Worksheet addedSheet = workbook.Worksheets.Add(Type.Missing,
workbook.Worksheets[count], Type.Missing, Type.Missing);
// get the reference of first sheet. By default its name is Sheet1.
// store its reference to worksheet
worksheet2 = workbook.Sheets["Sheet2"];
worksheet2 = workbook.ActiveSheet;
// changing the name of active sheet
worksheet2.Name = "Itemised Extn";
// storing header part in Excel
for (int i = 1; i < fullresult.Columns.Count + 1; i++)
{
worksheet2.Cells[1, i] = fullresult.Columns[i - 1].HeaderText;
}
// storing Each row and column value to excel sheet
for (int i = 0; i < fullresult.Rows.Count - 1; i++)
{
for (int j = 0; j < fullresult.Columns.Count; j++)
{
if (fullresult.Rows[i].Cells[j].Value == null)
{
fullresult.Rows[i].Cells[j].Value = "NA";
}
worksheet2.Cells[i + 2, j + 1] = fullresult.Rows[i].Cells[j].Value.ToString();
}
}
// save the application
string fileName = String.Empty;
SaveFileDialog saveFileDialog1 = new SaveFileDialog();
saveFileDialog1.Filter = "Excel files |*.xls|All files (*.*)|*.*";
saveFileDialog1.FilterIndex = 2;
saveFileDialog1.RestoreDirectory = true;
if (saveFileDialog1.ShowDialog() == DialogResult.OK)
{
fileName = saveFileDialog1.FileName;
workbook.SaveAs(fileName, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Microsoft.Office.Interop.Excel.XlSaveAsAccessMode.xlExclusive, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
}
else
return;
}
//Catch all errors.
catch (System.Exception)
{
}
finally
{
workbook = null;
app = null;
}
}
You probably might want to double-check your outer for loop again, e.g. for (int i = 0; i < fullresult.Rows.Count - 1; i++), shouldn't it be using less than and equal perhaps?
Since you are using Excel com interop, you will need to call this method to be able to release the resource after you are done with it, Marshal.ReleaseComObject.
A good practice is to use try{...}catch{...}finally{...}, and release com object in the finally block.

How to export excel file in c# in multiple sheets

I have this code that export an excel file using c# from 1 listview. My problem now is if I have 2 listviews that will be generated in 1 excel file, my plan is listview1 is for sheet1 and listview2 is for sheet2.
this is my code generates listview1 to excel into sheet1:
string[] st = new string[listView1.Columns.Count];
DirectoryInfo di = new DirectoryInfo(Environment.ExpandEnvironmentVariables("%USERPROFILE%") + #"\Desktop\");
if (di.Exists == false)
di.Create();
fileName f = new fileName();
if (f.ShowDialog() == DialogResult.OK)
{
StreamWriter sw = new StreamWriter(Environment.ExpandEnvironmentVariables("%USERPROFILE%") + #"\Desktop\" + f.Filenam + ".xls", false);
sw.AutoFlush = true;
string header = "";
for (int col = 0; col < listView1.Columns.Count; col++)
{
header += listView1.Columns[col].Text.ToString() + "\t";
}
sw.Write(header);
int rowIndex = 1;
int row = 0;
string st1 = "";
for (row = 0; row < listView1.Items.Count; row++)
{
if (rowIndex <= listView1.Items.Count)
rowIndex++;
st1 = "\n";
for (int col = 0; col < listView1.Columns.Count; col++)
{
st1 = st1 + listView1.Items[row].SubItems[col].Text.ToString() + "\t";
}
sw.Write(st1);
}
sw.Close();
FileInfo fil = new FileInfo(Environment.ExpandEnvironmentVariables("%USERPROFILE%") + #"\Desktop\" + f.Filenam + ".xls");
if (fil.Exists == true)
MessageBox.Show("Process Completed", "Export to Excel", MessageBoxButtons.OK, MessageBoxIcon.Information);
}
I have used EPPlus, its free, give performance benefits, and provides many Excel functions. Other option you can look for is Microsoft InterOp for Excel export, but it has performance problems.
As Irfan already mentioned, you could do that with Microsoft.Office.Interop
Excel.Application xlsApp = new Excel.Application();
Excel.Workbook workbook;
workbook = xlsApp.Workbooks.Open(configuration.XLSExportedFile, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing, Type.Missing);
foreach (Excel.Worksheet sheet in workbook.Sheets)
{
workbook.Activate();
sheet.Activate();
}
That would help you to step through all your sheets in your Excel file.
Now in case you want to expand it with multiple sheets, you can read C# how to add Excel Worksheet programmatically Office XP / 2003 in order to find how to add additional sheets.
What you could do now, is put your text into a variable for example HTML or any kind of information from your listbox.
string html = Clipboard.GetText(TextDataFormat.Html);
Now you can play around with the Clipboard(alternative solution, but to avoid).
Clipboard.SetText(html);
It actually enters information into your Clipboard, what you could do is pass all your listbox values into the Clipboard.
And now the final step would be to paste it at the position that you want.
sheet.Range(cellmapp).PasteSpecial();
Where cellmap is supposed to be for example A1. In case your text that you have in your listbox is too long you can adapt your rows/columns.
//Auto fits all columns and rows
//https://stackoverflow.com/questions/14748322/c-sharp-autofit-method-for-excel-sheet
sheet.Columns.AutoFit();
sheet.Rows.AutoFit();
Don't forget, if you work with COM processes, close every object and file.
workbook.SaveAs(configuration.XLSExportedFile);
workbook.Close();
xlsApp.Quit();
xlsApp.Dispose();
I don't say that would be the best solution to do, but you could look up for OpenXML also.
I've used ClosedXML before, the syntax is really clean and simple and you can get this sort of task done in just a few lines
This block shows how to add a list to a new sheet and save it
List<string> list = new List<string>();
var workbook = new XLWorkbook();
var worksheet = workbook.Worksheets.Add("Sample Sheet");
worksheet.Cell(1, 1).Value = list;
workbook.SaveAs("HelloWorld.xlsx");

Categories

Resources