I want to check if the sheet exists before creating it.
using Excel = Microsoft.Office.Interop.Excel;
Excel.Application excel = new Excel.Application();
excel.Visible = true;
Excel.Workbook wb = excel.Workbooks.Open(#"C:\"Example".xlsx");
Excel.Worksheet sh = wb.Sheets.Add();
int count = wb.Sheets.Count;
sh.Name = "Example";
sh.Cells[1, "A"].Value2 = "Example";
sh.Cells[1, "B"].Value2 = "Example"
wb.Close(true);
excel.Quit();
This extension method returns the worksheet if it exists, null otherwise:
public static class WorkbookExtensions
{
public static Excel.Worksheet GetWorksheetByName(this Excel.Workbook workbook, string name)
{
return workbook.Worksheets.OfType<Excel.Worksheet>().FirstOrDefault(ws => ws.Name == name);
}
}
The linq method .Any() can be used instead of FirstOrDefault to check whether the worksheet exists as well...
Create a loop like this:
// Keeping track
bool found = false;
// Loop through all worksheets in the workbook
foreach(Excel.Worksheet sheet in wb.Sheets)
{
// Check the name of the current sheet
if (sheet.Name == "Example")
{
found = true;
break; // Exit the loop now
}
}
if (found)
{
// Reference it by name
Worksheet mySheet = wb.Sheets["Example"];
}
else
{
// Create it
}
I'm not into Office Interop very much, but come to think of it, you could also try the following, much shorter way:
Worksheet mySheet;
mySheet = wb.Sheets["NameImLookingFor"];
if (mySheet == null)
// Create a new sheet
But I'm not sure if that would simply return null without throwing an exception; you would have to try the second method for yourself.
Why not just do this:
try {
Excel.Worksheet wks = wkb.Worksheets["Example"];
} catch (System.Runtime.InteropServices.COMException) {
// Create the worksheet
}
wks.Select();
The other way avoids throwing and catching exceptions, and certainly it's a legitimate answer, but I found this and wanted to put this up as an alternative.
Related
I want to create an Excel Workbook with one WorkSheet, then Save the data and close it. But it creates two Sheets. Sheet2 and Sheet1. It writes the data successfully though. Everytime I delete the xlsx file manually, it asks me for overwriting Book8.xlsx even though there is not such a file with this name.
I just want one worksheet and I want to have it with a specific name too, instead of Sheet1
class Program
{
static void Main(string[] args)
{
Excel excel = new Excel(#"d:\Test.xlsx", 1);
excel.WriteToCell(0, 0, "Test2");
excel.Save();
excel.SaveAs(#"d:\Test.xlsx");
excel.Close();
}
}
Inside Excel.cs
using Microsoft.Office.Interop.Excel;
using _Excel = Microsoft.Office.Interop.Excel;
namespace Excel
{
class Excel
{
_Application excel = new _Excel.Application();
Workbook wb;
Worksheet ws;
public Excel(string path, int Sheet)
{
excel.Visible = false;
wb = excel.Workbooks.Add();
ws = wb.Worksheets.Add();
}
public void WriteToCell(int i, int j, string s)
{
i++;
j++;
ws.Cells[i, j].Value = s;
}
public void Save()
{
wb.Save();
}
public void SaveAs(string path)
{
wb.SaveAs(path);
}
public void Close()
{
wb.Close();
}
}
}
Remove the line ws = wb.Worksheets.Add(); from Excel constructor to not create the second sheet.
public Excel(string path, int Sheet)
{
excel.Visible = false;
wb = excel.Workbooks.Add();
ws = (Worksheet)wb.Worksheets[1];
if (ws == null)
{
Console.WriteLine("Worksheet could not be created. Check that your office installation and project references are correct.");
}
}
To rename the worksheet:
public RenameWorksheet(string newName)
{
ws.Name = newName;
}
If you delete a file from a directory, it should be deleted. However, if you are having a pop saying the file exists and do you want to replace it then my guess is it is probably a human error here. Maybe you are looking under a wrong directory? Happens to the best of us at times ;) Either way as a programmer you can choose to delete the file if it exists before creation to avoid human errors:
if(File.Exists(fileName))
{
File.Delete(fileName);
}
or simply rename it if you don't want to replace it.
EDIT
On second look I realized you are creating a new file:
Excel excel = new Excel(#"d:\Test.xlsx", 1);
and then calling:
excel.SaveAs(#"d:\Test.xlsx");
what else do you expect?
I have a function to read an Excel, then workbook and sheet.
But the Excel thread never finish. I tried every solution i found around here but didn't work.
Excel thread stack on task manager, and at moment, my application crash because of Excel stop working.
public static object[,] ReadFile(string filepath, string sheetname)
{
Application xlApp = null;
Workbooks wks = null;
Workbook wb = null;
object[,] values = null;
try
{
xlApp = new ApplicationClass();
wks = xlApp.Workbooks;
wb = wks.Open(filepath, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing, missing);
Worksheet sh = (Worksheet)wb.Worksheets.get_Item(sheetname);
values = sh.UsedRange.Value2 as object[,];
System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sh);
sh = null;
}
catch (Exception ex)
{
throw new Exception(string.Format("Sheet \"{0}\" does not exist in the Excel file", sheetname));
}
finally
{
if (wb != null)
{
wb.Close(false);
Marshal.FinalReleaseComObject(wb);
wb = null;
}
if (wks != null)
{
wks.Close();
Marshal.FinalReleaseComObject(wks);
wks = null;
}
if (xlApp != null)
{
// Close Excel.
xlApp.Quit();
Marshal.FinalReleaseComObject(xlApp);
xlApp = null;
}
}
return values;
}
Maybe i don't do things in the right order, or maybe i understood wrong the COM object problem.
I had same issue I used below code to specifically kill the process
[DllImport("user32.dll")]
static extern int GetWindowThreadProcessId(int hWnd, out int lpdwProcessId);
Process GetExcelProcess(Excel.Application excelApp)
{
int id;
GetWindowThreadProcessId(excelApp.Hwnd, out id);
return Process.GetProcessById(id);
}
This method GetExcelProcesswill give you the exact process which you can kill manually. It will remove Excel.exe from task manager.
In my understanding it should not be necessary to explicitly release the com objects if you use a .NET wrapper object like excel interop. If excel still exists then I would look for errors in handling as something might be left over.
In the sample below the excel process stops already when it comes to the first console.ReadLine. In case it does not immediately stop try to hit enter to start a GC.
The following works for me and excel is stopped.
I used:
.NET Framework 4.5.2
Microsoft.Office.Interop.Excel 1.7.0.0
Excel 2010
Windows 7
using System;
using Microsoft.Office.Interop.Excel;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Go");
var t = ReadFile(#"<filename>", "<sheetname>");
Console.WriteLine("1");
Console.ReadLine();
GC.Collect();
GC.WaitForPendingFinalizers();
GC.Collect();
Console.ReadLine();
}
public static object[,] ReadFile(string filepath, string sheetname)
{
Application xlApp = null;
Workbooks wks = null;
Workbook wb = null;
object[,] values = null;
try
{
xlApp = new Application();
wks = xlApp.Workbooks;
wb = wks.Open(filepath);
Worksheet sh = (Worksheet)wb.Worksheets.get_Item(sheetname);
values = sh.UsedRange.Value2 as object[,];
//System.Runtime.InteropServices.Marshal.FinalReleaseComObject(sh);
//sh = null;
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
Console.WriteLine(string.Format("Sheet \"{0}\" does not exist in the Excel file", sheetname));
}
finally
{
if (wb != null)
{
wb.Close(false);
//Marshal.FinalReleaseComObject(wb);
wb = null;
}
if (wks != null)
{
wks.Close();
//Marshal.FinalReleaseComObject(wks);
wks = null;
}
if (xlApp != null)
{
// Close Excel.
xlApp.Quit();
//Marshal.FinalReleaseComObject(xlApp);
xlApp = null;
}
}
return values;
}
}
}
As a comment to the linked stackoverflow question on not using two dot commands. This sample worked on my machine also with two dot commands (opening a workbook). It did not make a difference. Excel was released and the process was closed. The excel sheet used for testing was a standard sheet with 3 fields filled in with numbers.
I am currently creating a small program that will allow a user to input data into a windows form. Once this data has been input into the form it will then be added to a Excel Document using OleDb.
I have no problems with the above section and I can input data no bother however my problem comes when I try to change the colour of the Excel Row.
I am looking to change the colour of the row to red if the row currently has no fill.
The code I am currently using:
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Open(#"C:\Users\jhughes\Desktop\ScreenUpdate.xls");
Excel.Worksheet worksheet = (Excel.Worksheet)workbook.Sheets["DailyWork"];
Excel.Range usedRange = worksheet.UsedRange;
Excel.Range rows = usedRange.Rows;
try
{
foreach (Excel.Range row in rows)
{
if (row.Cells.EntireRow.Interior.ColorIndex = 0)
{
row.Interior.Color = System.Drawing.Color.Red;
}
}
}
catch(Exception ex)
{
MessageBox.Show(ex.ToString());
}
I am getting the error "Cannot implicitly convert type int to bool" at the line "If(row.Cells.EntireRow....)"
You are attempting to set the ColorIndex to 0, not comparing it to 0. Use == when you compare.
foreach (Excel.Range row in rows)
{
if (row.Cells.EntireRow.Interior.ColorIndex == 0) // changed = to ==
{
row.Interior.Color = System.Drawing.Color.Red;
}
}
You need to use == operator instead of = operator. == operator for equality but = operator is for assignment.
if (row.Cells.EntireRow.Interior.ColorIndex == 0)
= operators simply assign right operand to the left variable/property/indexer and returns the value as its result. That's why when you write
if (row.Cells.EntireRow.Interior.ColorIndex = 0)
it is equal to
if(0)
which is won't compile since if statement expects boolean expression.
I think you not added saving to workbook and change in if condition. Somehow the default colorindex is coming as -4142. Tested now able to change the change color
Excel.Application application = new Excel.Application();
Excel.Workbook workbook = application.Workbooks.Open(#"C:\Users\MyPath\Desktop\ColorBook.xls");
Excel.Worksheet worksheet = (Excel.Worksheet)workbook.Sheets["DailyWork"];
Excel.Range usedRange = worksheet.UsedRange;
Excel.Range rows = usedRange.Rows;
try
{
foreach (Excel.Range row in rows)
{
if (row.Cells.EntireRow.Interior.ColorIndex == -4142)
{
row.Interior.Color = System.Drawing.Color.Red;
}
}
workbook.Save();
workbook.Close();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}
i need to check if a worksheet exist in excel and if not, to create it. I'm using infragistics and the following code gives me the following error:
use of unassigned local variable 'workSheet'.
this is the code:
Workbook workbook = new Workbook();
Worksheet workSheet;
foreach (Something result in results)
{
foreach (Something item in result.Something)
{
if (!workbook.Worksheets.Exists(item.GetType().Name))
{
workSheet = workbook.Worksheets.Add(item.GetType().Name);
}
// cell font
IWorkbookFont oFont = workSheet.Workbook.CreateNewWorkbookFont();
....
}
}
The error is about the: IWorkbookFont oFont = workSheet.Workbook.CreateNewWorkbookFont()
on the workSheet variable.
thanks.
Here is how you can avoid the error. Initialize worksheet to null when you declare it. Do not forget the null check before accessing the worksheet.
Workbook workbook = new Workbook();
Worksheet workSheet = null;
foreach (Something result in results)
{
foreach (Something item in result.Something)
{
if (!workbook.Worksheets.Exists(item.GetType().Name))
{
workSheet = workbook.Worksheets.Add(item.GetType().Name);
}
if (workSheet != null)
{
// cell font
IWorkbookFont oFont = workSheet.Workbook.CreateNewWorkbookFont();
....
}
....
}
}
I've found the answer:
Worksheet workSheet = null;
if (!workbook.Worksheets.Exists(item.GetType().Name))
{
workSheet = workbook.Worksheets.Add(item.GetType().Name);
}
else
{
workSheet = workbook.Worksheets[item.GetType().Name];
}
// cell font
IWorkbookFont oFont = workSheet.Workbook.CreateNewWorkbookFont();
I had to make sure the workSheet variable has values (initialized).
I am writing a program that will allow me to open excel spreadsheets and get some specific information off of them. Each sheet contains the same information that I need, but the information is not always in the same location.
I am trying to find a way to search for specific text in an Excel sheet and have the address of the cell that text is in.
For example:
If I was looking for the text "apples", the function will find the cell that contains apples and return its address (i.e., A5).
For accessing the Excel spreadsheet I am using Excel = Microsoft.Office.Interop.Excel.
I have been looking all weekend for an efficient way to to do this and have been horribly unsuccessful so far. Any help I can get would be greatly appreciated.
Edit:
This is part of a much larger project, but for this particular function, I have the ability to open and close the Excel file. I have yet to start writing the search function yet, because to be perfectly honest, I am not exactly sure on even how to go about doing this. But here is what I have at this point.
public string searchExcel(string findThis)
{
Excel.Application xlApp;
Excel.Workbook xlWorkBook;
Excel.WorkSheet xlWorkSheet;
object misvalue;
//This part will open the Excel document.
misValue = System.Reflection.Missing.Value;
xlApp = new Excel.ApplicationClass();
xlWorkBook = xlApp.Workbooks.Open("C:\\temp2\\excelDocument.xlsm",
0, true, 5, "", "", true, Microsoft.Office.Interop.Excel.XlPlatform.xlWindows,
"\t", false, false, 0, true, 1, 0);
//Search and get address of cell
//This part will close the Excel document
xlWorkBook.Close(true, misValue, misvalue);
xlApp.Quit();
releaseObject(xlWorkSheet);
releaseObject(xlWorkBook);
releaseObject(xlApp);
xlWorkSheet = null;
xlWorkBook = null;
xlApp = null;
}
private void releaseObject(object obj)
{
try
{
System.Runtime.Interopservices.Marshal.ReleaseComObject(obj);
obj = null;
}
catch(Exception e)
{
obj = null;
MessageBox.Show("Unable to release the object " + e.ToString());
}
finally
{
GC.Collect();
}
}
I think something like this should do what you want:
var app = (Excel.Application)Marshal.GetActiveObject("Excel.Application");
var wb = app.ActiveWorkbook;
var ws = wb.Worksheets[1] as Excel.Worksheet;
var cells = ws.Cells;
var match = cells.Find("apples", LookAt:=Excel.XlLookAt.xlPart) as Excel.Range;
var matchAdd = match != null ? match.Address : null;
This will search in the first Worksheet of the current active workbook of a current Excel session.
Adjusting to fit your code:
xlWorksheet = xlWorkBook.Worksheets[1] as Excel.Worksheet;
Excel.Range cells = ws.Cells;
Excel.Range match = cells.Find("apples", LookAt:=Excel.XlLookAt.xlPart) as Excel.Range;
string matchAdd = match != null ? match.Address : null;
if (match != null) releaseObject(match);
releaseObject(cells);
One thing, is this assumes .Net 4.0 as I use missing arguments for the find call. If you are using a previous version you will need to pass in misValue for any parameter not used.