C# Interop - Iterating through rows and deleting - c#

I am using Excel Interop to work with some excel sheets. In a worksheet, I need to iterate through the rows, and if the first cell in the row is empty then I need to delete the entire row iteself. I tried the following-
Excel.Range excelRange = sheet.UsedRange;
foreach (Excel.Range row in excelRange.Rows)
{
String a = ((Excel.Range)row.Cells[Type.Missing, 1]).Value2 as String;
if (a == null || a == "")
{
((Excel.Range)row).Delete(Type.Missing);
}
}
This was not working at all. Is there any different way to do this?
And, is there any quick way to find and remove all formula in a Worksheet?

Let's say your Excel file looks like this.
The best way to delete rows would be to use Excel's inbuilt feature called Autofilter which will filter Col A for blank values and then deleting the entire rows in one go.
TRIED AND TESTED (In VS 2010 Ultimate)
Note: I have changed few lines which I feel could error out in VS 2008. Since I don't have VS 2008, I couldn't test it there. If you get any errors do let me know and I will rectify it.
//~~> Open File
private void button1_Click(object sender, EventArgs e)
{
Microsoft.Office.Interop.Excel.Application xlexcel;
Microsoft.Office.Interop.Excel.Workbook xlWorkBook;
Microsoft.Office.Interop.Excel.Worksheet xlWorkSheet;
Microsoft.Office.Interop.Excel.Range xlRange;
Microsoft.Office.Interop.Excel.Range xlFilteredRange;
xlexcel = new Excel.Application();
xlexcel.Visible = true;
//~~> Open a File
xlWorkBook = xlexcel.Workbooks.Open("C:\\MyFile.xlsx", 0, false, 5, "", "", true,
Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
//~~> Work with Sheet1
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
//~~> Get last row in Col A
int _lastRow = xlWorkSheet.Cells.Find(
"*",
xlWorkSheet.Cells[1,1],
Excel.XlFindLookIn.xlFormulas,
Excel.XlLookAt.xlPart,
Excel.XlSearchOrder.xlByRows,
Excel.XlSearchDirection.xlPrevious,
misValue,
misValue,
misValue
).Row ;
//~~> Set your range
xlRange = xlWorkSheet.Range["A1:A" + _lastRow];
//~~> Remove any filters if there are
xlWorkSheet.AutoFilterMode=false;
//~~> Filter Col A for blank values
xlRange.AutoFilter(1, "=", Excel.XlAutoFilterOperator.xlAnd, misValue, true);
//~~> Identigy the range
xlFilteredRange = xlRange.Offset[1,0].SpecialCells(Excel.XlCellType.xlCellTypeVisible,misValue);
//~~> Delete the range in one go
xlFilteredRange.EntireRow.Delete(Excel.XlDirection.xlUp);
//~~> Remove filters
xlWorkSheet.AutoFilterMode = false;
//~~> Close and cleanup
xlWorkBook.Close(true, misValue, misValue);
xlexcel.Quit();
releaseObject(xlRange);
releaseObject(xlFilteredRange);
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlexcel);
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Unable to release the Object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
Output

Related

Export Chart to Excel File

I am new in C# Programming. I am creating a winform application in which I am using System.Windows.Forms.DataVisualization Chart. This chart contains multiple series. I want to export that chart data to Excel file.
To Add Data to chart I am using
chart.Series[mSeries].Points.AddXY(dt, avgData);
dt is current DateTime and the data.
So my Excel file look like
First Column is Series Name, second is DateTime and third column contain data.
So, can anyone please tell me how I can do this.
Thanks in Advance
You can refer to the following solution. First you will need to add reference to Microsoft Excel Object Library of COM. See this link on how to add. Then next step is pretty simple. You will need to add the code from the above link and replace the data which you fed in Excel with your custom data.
Here is the code shown in the link.
private void button1_Click(object sender, EventArgs e)
{
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Add(misValue);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
for (int i = 0; i < chart1.Series.Count; i++)
{
xlWorkSheet.Cells[1, 1] = "";
xlWorkSheet.Cells[1, 2] = "DateTime";//put your column heading here
xlWorkSheet.Cells[1, 3] = "Data";// put your column heading here
for (int j = 0; j < chart1.Series[i].Points.Count; j++)
{
xlWorkSheet.Cells[j + 2 , 2] = chart1.Series[i].Points[j].XValue;
xlWorkSheet.Cells[j + 2 , 3] = chart1.Series[i].Points[j].YValues[0];
}
}
Excel.Range chartRange;
Excel.ChartObjects xlCharts = (Excel.ChartObjects)xlWorkSheet.ChartObjects(Type.Missing);
Excel.ChartObject myChart = (Excel.ChartObject)xlCharts.Add(10, 80, 300, 250);
Excel.Chart chartPage = myChart.Chart;
chartRange = xlWorkSheet.get_Range("B2", "c5");//update the range here
chartPage.SetSourceData(chartRange, misValue);
chartPage.ChartType = Excel.XlChartType.xlColumnClustered;
xlWorkBook.SaveAs("csharp.net-informations.xls", Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
xlWorkBook.Close(true, misValue, misValue);
xlApp.Quit();
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);
MessageBox.Show("Excel file created , you can find the file c:\\csharp.net-informations.xls");
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Exception Occured while releasing object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
Simply replace the cells and data from the code with your custom data and viola when you click on export button it will export it for you.

Deleting a sheet in Excel

I tried almost everything that I could find here on StackOverflow but my code keeps throwing the following error:
Exception from HRESULT: 0x800A03EC
on the line with delete(). I was hoping you people could help me out.
Here's my current code
var xlApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook book =
xlApp.Workbooks.Open(File_name);
xlApp.DisplayAlerts = false;
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
book.Worksheets.Add();
xlApp.DisplayAlerts = true;
book.Save();
book.Close();
xlApp.Quit();
Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(book);
Marshal.ReleaseComObject(xlApp);
And here's the other code i tried:
oXL.DisplayAlerts = false;
worksheet = (Excel.Worksheet)theWorkbook.Sheets[i];
((Excel.Worksheet)theWorkbook.Sheets[i]).Delete();
oXL.DisplayAlerts = true;
oWB.Save();
oWB.Close(false, missing, missing);
oSheet = null;
oWB = null;
oXL.Quit();
And some more variations
Microsoft.Office.Interop.Excel.Application oXL = new Microsoft.Office.Interop.Excel.Application();
Excel.Workbook oWB;
Excel.Worksheet oSheet;
Excel.Workbooks oMWB;
and i'm using this reference:
using Excel = Microsoft.Office.Interop.Excel;
Working with the Excel Interop libraries, I encountered this error many times. The main cause of this problem (a generic COM exception), most of the times, is that Excel tries to find something you've asked for, but Excel isn't able to find it. See this answer, it helped me a lot.
Reading these lines:
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
I think that you're trying to delete a worksheet that's not existing. Check your Excel document.
I just made the most stupid mistake ever..... the excel file was a shared file, that's why i couldn't delete it..
Sorry for making such a stupid mistake, and thanks to everybody who tried to help me!
HRESULT: 0x800A03EC is an unknown COM error. This usually happens when Excel throws some error because your input or parameters were wrong.
This example provide msdn: Programmatically Deleting Worksheets from Workbooks
((Excel.Worksheet)this.Application.ActiveWorkbook.Sheets[4]).Delete();
So try next:
Excel.Worksheet worksheet = (Excel.Worksheet)book.Sheets[2];
worksheet.Delete();
instead of:
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
Try this:
xlApp.DisplayAlerts = false;
Excel.Worksheet worksheet = (Excel.Worksheet)book.Worksheets[2];
worksheet.Delete();
xlApp.DisplayAlerts = true;
Also important to keep in mind, interop starts to count from 1, not from 0. so deleting item [0] or deleting the only sheet will throw you an exception. if you plan to remove the [2] worksheet, the third one will take its place. So make sure to remove from the last to the first.
this is code i have used to delete the excel sheet
Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
if (xlApp == null)
{
return;
}
xlApp.DisplayAlerts = false;
string filePath = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)
+ "\\Sample.xlsx";
Excel.Workbook xlWorkBook = xlApp.Workbooks.Open(filePath, 0, false, 5, "", "", false, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Excel.Sheets worksheets = xlWorkBook.Worksheets;
worksheets[4].Delete();
worksheets[3].Delete();
xlWorkBook.Save();
xlWorkBook.Close();
releaseObject(worksheets);
releaseObject(xlWorkBook);
releaseObject(xlApp);
and use this
static void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
throw ex;
}
finally
{
GC.Collect();
}
}

Excel.Worksheet.Cells has reversed behavior?

Hey all, I'm experiencing transposed behavior when working the Excel.Worksheet.Cells array.
My first cell needs to be at [row = 10, column = 3]
My second cell needs to be at [row = 11, column = 17]
Then using these two cells as boundaries, I create a range and merge it.
As you can tell from the values noted above, the range should be mostly horizontal.
So, to help me out, I created a simple helper function that merges cells:
public static void MergeRange(Excel.Worksheet worksheet, int startRowIdx,
int startColIdx, int endRowIdx, int endColIdx, bool across = false)
{ //Get range boundaries.
Excel.Range cells = worksheet.Cells;
//commented out, resolved code is directly below - N. Miller, 9-24-2013
//Excel.Range topleftCell = cells[startColIdx][startRowIdx];
//Excel.Range bottomrightCell = cells[endColIdx][endRowIdx];
Excel.Range topleftCell = cells[startRowIdx, startColIdx];
Excel.Range bottomrightCell = cells[endRowIdx, endColIdx];
//Merge range.
Debug.WriteLine(String.Format("({0}, {1}) to ({2}, {3}).", startRowIdx, startColIdx, endRowIdx, endColIdx));
Excel.Range range = worksheet.get_Range(topleftCell, bottomrightCell);
Excel.Interior interior = range.Interior;
interior.ColorIndex = XLColor.PERIWINKLE; //JUST HIGHLIGHTS RANGE FOR NOW.
//range.Merge(across);
//Cleanup
Marshal.ReleaseComObject(interior);
Marshal.ReleaseComObject(range);
Marshal.ReleaseComObject(bottomrightCell);
Marshal.ReleaseComObject(topleftCell);
Marshal.ReleaseComObject(cells);
}
In the code above, I select the cells I want by swapping the columns and rows. This, contrary to what I expected, results in the desired behavior, but it contradicts the MSDN documentation:
MSDN Worksheet.Cells
In the MSDN documentation they give an example where the row is listed first, then the column follows after.
So my question is this... which is correct?
Should the row be first, or should the column be first?
When I modify my code to be consisten with the MSDN documentation, the highlighted cells are transposed.
If I understand you correctly then when you use say cells[1][2] then it means A2 In such a case, Column comes first and then the row. If you write it as cells[1,2] then you will get B2. In this case, Row comes first and then the Column.
It's the same in Excel-VBA. ?Cells(1)(2).address in immediate window gives $A$2 and ?Cells(1,2).address gives $B$1 If you feel that I have not understood your query then please re-phrase it for me...
Here is the complete code to test it.
NOTE: Tested using VS 2010 Ultimate + Excel 2010
using System;
using System.Windows.Forms;
using System.IO;
using Excel = Microsoft.Office.Interop.Excel;
using System.Reflection;
Namespace WindowsFormsApplication1
{
public partial class Form1 : Form
{
Public Form1()
{
InitializeComponent();
}
private void button1_Click(object sender, EventArgs e)
{
Excel.Application xlexcel;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = Missing.Value;
xlexcel = new Excel.Application();
xlexcel.Visible = true;
//~~> Open a File (Change filename as applicable)
xlWorkBook = xlexcel.Workbooks.Open("C:\\SomeFile.xlsx",
0, true, 5, "", "", true,
Microsoft.Office.Interop.Excel.XlPlatform.xlWindows,
"\t", false, false, 0, true, 1, 0);
//~~> Set Sheet 1 as the sheet you want to work with
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
Excel.Range cells = xlWorkSheet.Cells;
Excel.Range topleftCell = cells[1][2];
MessageBox.Show(topleftCell.Address);
topleftCell = cells[1,2];
MessageBox.Show(topleftCell.Address);
//~~> Once done close and quit Excel
xlWorkBook.Close(false, misValue, misValue);
xlexcel.Quit();
//~~> CleanUp
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlexcel);
}
private void releaseObject(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch (Exception ex)
{
obj = null;
MessageBox.Show("Unable to release the Object " + ex.ToString());
}
finally
{
GC.Collect();
}
}
}
}
ScreenShot

How to create a new worksheet in Excel file c#?

I need to create a very big Excel file, but excel file in one worksheet can contain up to 65k rows. So, i want to divide all my info into several worksheets dynamical.
This is my approximate code
//------------------Create Excel App--------------------
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlApp = new Excel.Application();
xlWorkBook = xlApp.Workbooks.Add(misValue);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(numberOfLetters);
foreach (string letter in letters)
{
xlWorkSheet.Cells[rowIndex, 1] = letter;
rowIndex++;
}
xlWorkBook.SaveAs(pathXL, Excel.XlFileFormat.xlWorkbookNormal, misValue, misValue, misValue, misValue, Excel.XlSaveAsAccessMode.xlExclusive, misValue, misValue, misValue, misValue, misValue);
xlWorkBook.Close(true, misValue, misValue);
xlApp.Quit();
How I can add new worksheet inside of my foreach loop and using some condition give a name to worksheet (which user can see in Excel at the bottom of the page in list)?
Some like that
foreach (string letter in letters)
{
if (letter == SOME)
{
AddNewWorksheet and give name SOME
}
xlWorkSheet.Cells[rowIndex, 1] = letter;
rowIndex++;
}
And how to save all worksheets at the end?
To add a new worksheet to the workbook use this code:
var xlSheets = xlWorkBook.Sheets as Excel.Sheets;
var xlNewSheet = (Excel.Worksheet)xlSheets.Add(xlSheets[1], Type.Missing, Type.Missing, Type.Missing);
xlNewSheet.Name = "newsheet";
// Uncomment a line below if you want the inserted sheet to be the last one
//xlWorkBook.Sheets.Move(After: xlWorkBook.Sheets.Count);
To save the workbook call Save() method:
xlWorkBook.Save();
This is the correct code that is given in MSDN.
Excel.Worksheet newWorksheet;
newWorksheet = (Excel.Worksheet)Globals.ThisWorkbook.Worksheets.Add(
missing, missing, missing, missing);
For more information please click the link
In General when you want to create new sheet just do :
var worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.Worksheets.Add();
knowing that you already created the workbook like below :
var workbook = excel.Workbooks.Add(Type.Missing);
You are limited to 65,000 records with .xls , but if you are "allowed" to step beyond .xls / 2003 and into 2007 and above with .xlsx you should have a lot more rows.
Side note, nothing to do with your question, but a while back I had export to excel issues with RDLC and sheet names I renamed using NPOI library, since then I started using NPOI a lot more it is free /open source and very powerful (ported from Java POI to .net NPOI) again while I say it is not really a part of what your question is I wouldn't be surprised if it had examples on doing this (no I don't work for them ) http://npoi.codeplex.com/
Here is the code I had written for renaming sheets (which ends up re-creating the sheets with another memorystream
------------------------------------------------------------
var excelHelper = new ExcelHelper(bytes);
bytes = excelHelper.RenameTabs("Program Overview", "Go Green Plan", "Milestones", "MAT and EOC", "Annual Financials", "Risk Log", "Risk & Opportunity Log", "RAIL", "Meeting Minutes");
Response.BinaryWrite(bytes);
Response.End();
------------------------------------------------------------
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.IO;
using NPOI.HSSF.UserModel;
namespace Company.Project.Core.Tools
{
public class ExcelHelper
{
private byte[] _ExcelFile;
public ExcelHelper(byte[] excelFile)
{
_ExcelFile = excelFile;
}
public byte[] RenameTabs(params string[] tabNames)
{
byte[] bytes = null;
using (MemoryStream ms = new MemoryStream())
{
ms.Write(_ExcelFile, 0, _ExcelFile.Length);
var workBook = new HSSFWorkbook(ms, true);
if (tabNames != null)
{
using (MemoryStream memoryStream = new MemoryStream())
{
for (int i = 0; i < tabNames.Length; i++)
{
workBook.SetSheetName(i, tabNames[i]);
}
workBook.Write(memoryStream);
bytes = memoryStream.ToArray();
}
}
}
_ExcelFile = bytes;
return bytes;
}
}

C# code to Hide toolbars in an excel document

I have a C# Winforms program that opens an excel document with the code below.
It works great but what I can not figure out how to do, is to turn off ALL menu's and toolbars.
The excel version I am using right now is 2003... But I will be upgrading to 2010 in the near future.
Any ideas?
//top of source...
using Excel = Microsoft.Office.Interop.Excel;
// Code inside a function...
// Get report and display it on the screen.
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.Worksheet xlWorkSheet;
object misValue = System.Reflection.Missing.Value;
xlApp = new Excel.ApplicationClass();
xlWorkBook = xlApp.Workbooks.Open(strFileName, 0, true, 5, "", "", true,Excel.XlPlatform.xlWindows, "\t", false, false, 0, true, 1, 0);
xlWorkSheet = (Excel.Worksheet)xlWorkBook.Worksheets.get_Item(1);
xlApp.Visible = true;
xlApp.DisplayFullScreen = true;
// Display the Document and then Sleep.
System.Threading.Thread.Sleep(timeToShowMilliseconds);
// Close the Excel report
xlWorkBook.Close(false, misValue, misValue);
xlApp.Quit();
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);
I've been looking into your case and i think with Excel.Application you can find the answer.
Apparently what you need to do is something like this:
Excel.Application xlApp;
xlApp.CommandBars("tabName").Controls("File").Enabled = false;
try it and let me know, if it doesnt work we'll figure something out.

Categories