c# excel how to Find First Cell in a used range. - c#

I can use XlCellType.xlCellTypeLastCell to find last cell in the used range. How to get first cell in one line ?
Code to get last cell position.
Excel.Range mergeCells = (Excel.Range)mergeSheet.Cells[6,1].EntireRow;
var rowRng = mergeCells.SpecialCells(XlCellType.xlCellTypeLastCell, Type.Missing);
var colPosition = rowRng.Column;
One way is to get mergeCells.value and loop through to increment a counter until I see null/empty value. But I was hoping to get this in one line.
Any ideas ?
Test Cases:
(1)
Expected Result colPosition = 1
(2)
Expected Result colPosition = 5

Here is a solution using the Excel Interop library (as tagged in the question). The below method will return a 1-based column index of the first cell in a given row. It worked for me on your supplied test cases as well as a few of my own. Note that if you wish to simply use the first row in the used range - rather than a supplied row, you can find the first used row number using ActiveSheet.UsedRange.Rows[1].Row.
public static int FindFirstCellInExcelRow(string filePath, int rowNum)
{
Excel.Application xlApp = null;
Excel.Workbook wkBook = null;
Excel.Worksheet wkSheet = null;
Excel.Range range = null;
try
{
xlApp = new Excel.Application();
wkBook = xlApp.Workbooks.Open(filePath);
wkSheet = wkBook.ActiveSheet;
range = wkSheet.Cells[rowNum, 1].EntireRow;
if (range.Cells[1, 1].Value != null)
{
return range.Cells[1, 1].Column;
}
var result = range.Find(What: "*", After: range.Cells[1, 1], LookAt: Excel.XlLookAt.xlPart, LookIn: Excel.XlFindLookIn.xlValues, SearchOrder: Excel.XlSearchOrder.xlByColumns, SearchDirection: Excel.XlSearchDirection.xlNext, MatchByte: false, MatchCase: false);
int colIdx = result?.Column ?? 0; // return 0 if no cell in row contains value
return colIdx;
}
finally
{
wkBook.Close();
Marshal.ReleaseComObject(xlApp);
Marshal.ReleaseComObject(wkBook);
Marshal.ReleaseComObject(wkSheet);
Marshal.ReleaseComObject(range);
xlApp = null;
wkBook = null;
wkSheet = null;
range = null;
}
}

I highly (x10) recommend using ClosedXML over Microsoft's Excel libraries (unless you are using the old xls files). Using ClosedXML you would do the following (this is taken right from their webpage):
Get it right off the NuGet packages. Install-Package ClosedXML -Version 0.93.1
https://github.com/ClosedXML/ClosedXML/wiki/Finding-and-extracting-the-data
var wb = new XLWorkbook(northwinddataXlsx);
var ws = wb.Worksheet("Data");
// Look for the first row used
var firstRowUsed = ws.FirstRowUsed();
// Narrow down the row so that it only includes the used part
var categoryRow = firstRowUsed.RowUsed();
// Move to the next row (it now has the titles)
categoryRow = categoryRow.RowBelow();
// Get all categories
while (!categoryRow.Cell(coCategoryId).IsEmpty())
{
String categoryName = categoryRow.Cell(coCategoryName).GetString();
categories.Add(categoryName);
categoryRow = categoryRow.RowBelow();
}

try the below code snippet, this will give the first row of a excel used range
Excel.Workbook xlWB = Globals.ThisAddIn.Application.ActiveWorkbook;
Excel.Worksheet xlWS = xlWB.ActiveSheet;
int firstRow = xlWS.UsedRange.Row;

Related

Microsoft.Office.Interop.Excel cells remain null after setting them

I have an application in which I'm trying to write to an Excel file. It doesn't seem to be working.
Here is my code:
using System;
using System.Drawing;
using Microsoft.Office.Interop.Excel;
namespace Image2Excel {
class Engine {
public static void go(string imageFilename, string excelFilename = null) {
//Image img = Image.FromFile(imageFilename);
Bitmap btm = (Bitmap)Bitmap.FromFile(imageFilename, false);
Image img = Image.FromFile(imageFilename, false);
if (btm != null) {
Color[][] colorArray = new Color[btm.Width][];
for (int x = 0; x < btm.Width; x++) {
colorArray[x] = new Color[btm.Height];
for (int y = 0; y < btm.Height; y++) {
colorArray[x][y] = btm.GetPixel(x, y);
}
}
var excel = new Microsoft.Office.Interop.Excel.Application();
var workbook = excel.Workbooks.Add(Type.Missing);
var worksheet = (Microsoft.Office.Interop.Excel.Worksheet)workbook.ActiveSheet;
worksheet.Name = "sheet1";
worksheet.Cells[1,1] = "top left";
worksheet.Cells[1,2] = "top right";
worksheet.Cells[2,1] = "bottom left";
worksheet.Cells[2,2] = "bottom right";
workbook.SaveAs("temp.xlsx");
workbook.Close();
excel.Quit();
Marshal.ReleaseComObject(worksheet);
Marshal.ReleaseComObject(workbook);
Marshal.ReleaseComObject(excel);
}
}
}
}
I'm trying to write some text to the first 4 cells in the spreadsheet. It's not working. When I open the file, I see nothing in the cells.
I do see that the sheet name is set to what I set it to so I know it's writing to the files.
One thing I noticed when I debug is that worksheet.Cells[1,1] is null after I set it. I'm wondering if I need to set the cell to an object before writing to it. But I'm not sure how. I don't seem to be able to do this:
worksheet.Cells[1,1] = new Microsoft.Office.Interop.Excel.Cell();
Hovering over Cells tells me it's a Range object, but I'm not sure how to set it to a range either. I tried this:
worksheet.Range["A1"].Value = "hello";
worksheet.Range["A1"].Value2 = "hello";
...but those don't work either. worksheet.Range remains null just like worksheet.Cells.
How can I make sure worksheet.Cells[1,1] or worksheet.Range["A1"] is set to an object that will take a string value? Thanks.
You can find my application on github: https://github.com/gibran-shah/Image2Excel
I'm using Microsoft.Office.Interop.Excel version 15.0.4795.1000.
I have Excel 2010 installed on my computer.
I haven't tried yours but could you try these methods? it worked for me.
1st method with Worksheets.Cells
// CREATE EXCEL OBJECTS.
Excel.Application xlApp;
Excel.Workbook xlWB;
Excel.Worksheet xlWS;
xlApp = new Excel.Application();
// Specify the path to the excel file
xlWB= xlApp.Workbooks.Open("path/to/xlFile.xls");
// Choose the sheet you want to open
xlWS = xlWB.Worksheets["Sheet1"];
// Write on the single cell
xlWS.Cells["1", "D"] = "Example";
// Save the change and quit
xlWB.Close(true);
xlApp.Quit();
2nd method with Worksheets.get_Range()
// CREATE EXCEL OBJECTS.
Excel.Application xlApp;
Excel.Workbook xlWB;
Excel.Worksheet xlWS;
xlApp = new Excel.Application();
// Specify the path to the excel file
xlWB= xlApp.Workbooks.Open("path/to/xlFile.xls");
// Choose the sheet you want to open
xlWS = xlWB.Worksheets["Sheet1"];
// Write on the range of cells
xlWS.get_Range["A3", "D5"] = "Example";
// Save the change and quit
xlWB.Close(true);
xlApp.Quit();

Last Row in a column in excel file using C# (cells does not have get_end method)

When I try and call Cells[fullRow, 1].get_end I get an error, object does not contain a definition for get_end and no extension method could be found.
I never saw anyone complain about this or describe this in comments of old stack overflow threads re the subject of finding last row in an excel column using C#
string path = #"Z:\New folder\Test123.xlsx";
MyApp = new Excel.Application();
MyApp.Visible = true;
MyBook = MyApp.Workbooks.Open(path);
MySheet = (Excel.Worksheet)MyBook.Sheets[1];
int fullRow = MySheet.Rows.Count;
int LastRow = MySheet.Cells[1,1].get_end(Excel.XlDirection.xlUp).Row;
If you assign the return from MySheet.Cells[1, 1] in to a Range object or call the function End, you should find that it works as expected.
Also, note the case of the function, it is meant to be: get_End.
// Working
Excel.Range firstCell1 = MySheet.Cells[1, 1];
int LastRow1 = firstCell1.get_End(Excel.XlDirection.xlUp).Row;
// Working
Excel.Range firstCell2 = MySheet.Cells[fullRow, 1];
int LastRow2 = firstCell2.get_End(Excel.XlDirection.xlUp).Row;
// Working
int LastRow3 = MySheet.Cells[fullRow, 1].End(Excel.XlDirection.xlUp).Row;
// Does not work
int LastRow4 = MySheet.Cells[1, 1].get_End(Excel.XlDirection.xlUp).Row;
I believe the problem is down to the Dynamic Binding done at runtime for COM Interop, but, I am not 100% certain of the reason.
You can use something like this
void Main()
{
Microsoft.Office.Interop.Excel.Application app;
Microsoft.Office.Interop.Excel.Workbook wkb;
app = new Microsoft.Office.Interop.Excel.Application();
wkb = app.Workbooks.Open(#"e:\temp\test.xlsx");
int row = GetLastRow(wkb, "sheet1", "A");
Console.WriteLine(row);
app.Quit();
}
int GetLastRow(Workbook wkb, string sheet, string column)
{
Microsoft.Office.Interop.Excel.Worksheet sht = wkb.Worksheets[sheet] as Worksheet;
Microsoft.Office.Interop.Excel.Range range = sht.Range[column + ":" + column];
range = range.Cells[range.Rows.Count, range.Column] as Range;
return range.End[XlDirection.xlUp].Row;
}
You can remove all that Microsoft.Office.Interop.Excel stuff adding the appropriate using directive.

Set Excel Range For Unknown No. Of Columns

As you can see, the no. of columns names generated from column 4 are unknown. How can I set the range, so that I can apply the styles.
using Microsoft.Office.Interop;
using Excel = Microsoft.Office.Interop.Excel;
private void OpenExcel()
{
Excel.Application app = new Excel.Application();
Excel.Workbook wb = null;
Excel.Worksheet ws = null;
Excel.Range range = null;
app.visible = true;
wb = app.Workbooks.Add(1);
ws = (Excel.Worksheet)wb.WorkSheets[1];
//range = ws.get_Range("A1","D1");
ws.Cells[1,1]="Date";
ws.Cells[1,2]="Code";
ws.Cells[1,3]="Name";
IEnumerable<tblCountry> tbl = objDAL.GetRecords();
int i=4;
foreach(var item in tbl)
{
ws.Cells[1,i] = item.TypeCode;
i++;
}
range.Borders.Color = System.Drawing.Color.Black.ToArgb();
range.Interior.Color = System.Drawing.Color.PeachPuff.ToArgb();
range.Font.Bold = true;
}
Just use 3+ tbl.Count() as the last column?
//remember to initialise tbl first
IEnumerable<tblCountry> tbl = objDAL.GetRecords();
range=ws.get_Range((Excel.Range)ws.Cells[1, 1], (Excel.Range)ws.Cells[1, 3 + tbl.Count()]);
Use the End() function as follows to select row with all the columns.
range = ws.Range("A1").End(xlToLeft).Select
And then perform the Style operations.
range.Borders.Color = System.Drawing.Color.Black.ToArgb();
range.Interior.Color = System.Drawing.Color.PeachPuff.ToArgb();
range.Font.Bold = true;
The start range address is "A1" for this example, but I am sure in your Production code, you'll have the Range address as a parameter or coming from a variable.
For a detailed list of Range selection operations, see here. http://www.ozgrid.com/VBA/ExcelRanges.htm
You can pretty much use any of those VBA methods in this Interop in C#.

How to check if a cell is empty (Excel\VisualC#)

My aim is to check line per line in the Sheet1 in order to discover how many rows are, so i put a do\while that should stop once it reaches a blank cell
Example:
row1 data row2 data row3 datarow4 datarow5 data
row6 data row7 data
In this case I need only the first 5 rows, so the do\while check is intended to stop once it reaches the blank cell. This doesn't happens, because the check doesn't loop (it stops after completing a circle like it finds a blank cell even if it is filled with data).
string str;
int rCnt = 11; //the data I need is after the 10th row in excel
int cCnt = 1;
int valori = 1;
Excel.Application xlApp = new Excel.Application();
Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(label4.Text, 0, false, 5, "", "",
false, Excel.XlPlatform.xlWindows,
"", true, false, 0, true, false,
false);
Excel.Sheets xlsheet = xlWorkbook.Worksheets;
string sheet1 = "Sheet1";
Excel.Worksheet xlWorksheet = (Excel.Worksheet)xlsheet.get_Item(sheet1);
Excel.Range xlCell;
do
{
rCnt++;
str = "A" + rCnt;
xlCell = (Excel.Range)xlWorksheet.get_Range(str, str);
} while (xlCell.Value2 == null);
I tried changing Value2 to Value or Text and trying to set == "" instead of null.
If you want the loop stop when reach blank cell then .. Try to change
while (xlCell.Value2 == null);
with
while (! IsNull(xlCell.Value2));
Simple way to check a cell is empty:
if (sheet.Cells[4,3] == null || sheet.Cells[4,3].Value2 == null || sheet.Cells[4,3].Value2.ToString() == "")
MessageBox.Show(“cell on row 4 col 3 is empty”);
You can use the Text property of the selected cell. It can be converted to a string type via "as". The result string can already be checked as usual in C#, like not-empty
string TempText = excelWorksheet.Cells[1, 1].Text as string;
if (!string.IsNullOrWhiteSpace(TempText)){
// actions
}
The issue mainly comes from when you don't know what sort of data to expect. When I work with Excel reads I often do something similar to:
var _cell = range.Cells[1, 2].Value2;
if (_cell.GetType() != typeof(Double))
In your instance if you always are getting a string returned then you should be able to assume the cast:
string _str = (string)(range.Cells[str, str] as Excel.Range).Value2;
and then check that is not empty.
This is working for me:
using Excel = Microsoft.Office.Interop.Excel; to read excelsheet:
var excelApp = new Excel.Application();
Excel.Workbook excelWorkbook = excelApp.Workbooks.Open(path, 0, false, 5, "", "", false, XlPlatform.xlWindows, "", true, false, 0, true, false, false);
Excel.Worksheet excelWorksheet = (Excel.Worksheet)excelWorkbook.Sheets[2];
Excel.Range excelRange = excelWorksheet.UsedRange;
int rowCount = excelRange.Rows.Count;
int colCount = excelRange.Columns.Count;
string wwdEmpty = Convert.ToString(excelRange.Cells[5, 14].value2);
// this is working code with NULL Excell cell
do
{
rCnt++;
str = Sheet.Cells[rCnt, 5].Value;
} while (str != null);

C# - Excel: Delete Row, depending on value in first Column

Imagine, that u have the Column A.
There are 100 Rows and in the Cells are Numbers, like 1, 2, 3 until 100..
How can I programmaticaly (C#) Delete a specific Row, by Example: Deleting the Row which
Value in Column A is 5..
I'm working with the Microsoft.Office.Interop.Excel and thats the related code:
Microsoft.Office.Interop.Excel.Application xlApp = new Microsoft.Office.Interop.Excel.Application();
Microsoft.Office.Interop.Excel.Workbook xlWorkbook = xlApp.Workbooks.Open(#"C:\Users\fre\Desktop\TestDatei.xls");
Microsoft.Office.Interop.Excel._Worksheet xlWorksheet = xlWorkbook.Sheets[1];
Microsoft.Office.Interop.Excel.Range xlRange = xlWorksheet.UsedRange;
xlWorksheet.Select(Type.Missing);
Microsoft.Office.Interop.Excel.Range range = xlWorksheet.get_Range("B1:B5", Type.Missing);
range.Delete(Microsoft.Office.Interop.Excel.XlDeleteShiftDirection.xlShiftUp);
because i was interested, too, i did some investigation on the web and created some sample code. maybee this can help you:
private void DeleteCells(object sender, EventArgs e)
{
// create excel-instance:
Excel.Application excel = new Excel.Application();
// open the concrete file:
Excel.Workbook excelWorkbook = excel.Workbooks.Open(#"D:\test.xls");
// select worksheet. NOT zero-based!!:
Excel._Worksheet excelWorkbookWorksheet = excelWorkbook.Sheets[1];
// create a range:
Excel.Range usedRange = excelWorkbookWorksheet.UsedRange;
// iterate range
foreach (Excel.Range r in usedRange)
{
// check condition:
if (r.Value2 == 5.0F)
// if match, delete and shift remaining cells up:
r.Delete(Excel.XlDeleteShiftDirection.xlShiftUp);
}
// save changes (!!):
excelWorkbook.Save();
// cleanup:
if (excel != null)
{
Process[] pProcess;
pProcess = System.Diagnostics.Process.GetProcessesByName("Excel");
pProcess[0].Kill();
}
}
greetings!
jens
If you want to delete the entire row, try this it works
Range usedRanage=sheet.UsedRange;
foreach (Range r in usedRanage)
{
if (Convert.ToString(r.Value2)=="RETRIEVE")
{
r.EntireRow.Delete(XlDeleteShiftDirection.xlShiftUp);
}
}

Categories