How to get the address of a cell - c#

I'm trying to find the address of a cell in a xlsx file using c#, but i can't find a right solution for it.
using IronXL;
var workbook = IronXL.WorkBook.Load("email list.xlsx");
var sheet = workbook.WorkSheets.First();
var cells = sheet["A1:C494"];
foreach(var cell in cells)
{
Console.WriteLine(cell.Value);
//print cell adress
}
Thank you for your time

Related

Using NPOI to Retrieve the Value of a Merged Cell from an Excel Spreadsheet

I'm using NPOI to retrieve data from Excel into a text file. Based on the Excel sheet I'm supposed to show the data in this manner.
The cell for 13/3/19 in the Excel sheet is merged across two rows and I don't know how I can retrieve the merge cell value for May and display it. Does anyone have any ideas?
In Excel, if a cell is merged with other cells, the first cell in the merged region is the one that has the actual value. The other cells in the region are blank. The merged regions are kept in the worksheet object, since they can span multiple rows and columns.
To get the value, you need to:
Check whether the current cell is merged by looking at the IsMergedCell property on the cell itself.
If the cell is merged, loop through the merged regions on the worksheet to find the one containing that cell.
Once the containing region is found, get the first cell from the region.
Get the value from that cell.
Here is a helper method I wrote which should do the trick:
public static ICell GetFirstCellInMergedRegionContainingCell(ICell cell)
{
if (cell != null && cell.IsMergedCell)
{
ISheet sheet = cell.Sheet;
for (int i = 0; i < sheet.NumMergedRegions; i++)
{
CellRangeAddress region = sheet.GetMergedRegion(i);
if (region.ContainsRow(cell.RowIndex) &&
region.ContainsColumn(cell.ColumnIndex))
{
IRow row = sheet.GetRow(region.FirstRow);
ICell firstCell = row?.GetCell(region.FirstColumn);
return firstCell;
}
}
return null;
}
return cell;
}
Then as you are looping through your cells you can just call this method for every cell. If the cell is merged, it will return the cell that has the value for that merged region, otherwise it will just return the original cell back. So then you don't have to think about it anymore.
cell = GetFirstCellInMergedRegionContainingCell(cell);
if (cell != null)
{
// get the value
}

Updating a cell value breaks row style. NPOI, C#

Good evening, recently i was trying to update cell's value in .xls file, using NPOI library(C#), but, when i do that with cell.SetCellValue("anyvalue");,
I am able to see the changes only in some cells. Other cell are just empty.
Tried to save cell's style and re-write it using cell.CellStyle, but still the same.
Generally speaking, i get only half of the values that have to be filled in places.
Using that code, where nameAndValues[0] contains cell name, and nameAndValues[1] contains its value.
using (FileStream rstr = new FileStream(currentPath + $"/{excelName}", FileMode.Open, FileAccess.Read))
{
var workbook = new HSSFWorkbook(rstr);
var sheet = workbook.GetSheetAt(0);
using (FileStream wstr = new FileStream(currentPath + $"/{excelName}", FileMode.Open, FileAccess.Write))
{
for (int i = 0; i < values.Count; i++)
{
var cr = new CellReference(namesAndValue[i, 0]);
var row = sheet.CreateRow(cr.Row);
var cell = row.CreateCell(cr.Col);
cell.SetCellValue(namesAndValue[i, 1]);
}
workbook.Write(wstr);
wstr.Close();
}
rstr.Close();
}
When you call sheet.CreateRow(0), the first row of the sheet will be wiped out and an empty row will be inserted with no style. The same goes with row.CreateCell().
So you are calling CreateRow over and over again, making only the last value of the row survive.
I think this might be the problem.

Export on .xlsxm file

In my WinApp I export data to a specific tab of an Excel spreadsheet, in which there are macros (file extension .xlxm).
In this workbook, the data is always inserted from the same cell when it is empty, but it can happen that has already had the previous entries, so you have to retrieve the first available blank cell on the new line after the one that has already had the data inserted. The sequence of entries in the cells is similar to the following: in cells A1: A3, and then such as A10: A15, dropping the cells A4 to A9 because they are cells with formulas. I would to add that I must to control every cell of workbook for to fill in data from winApp. I hope to be able to explain the scenario.
You could use a library such as EPPlus from NuGet to achieve this. Something like this would do the trick.
static void Main(string[] args)
{
List<string> ExampleData = new List<string> { "my", "intestesting", "data" };
using (ExcelPackage package = new ExcelPackage(new FileInfo(#"C:\Temp\example.xlsm")))
{
ExcelWorksheet ws = package.Workbook.Worksheets["MySheet"];
int lastRowIndex = ws.Dimension.End.Row;
int idx = lastRowIndex + 1;
foreach (var datum in ExampleData)
{
ws.Cells[idx, 1].Value = datum;
idx++;
}
package.Save();
}
}

open xml sdk excel formula recalculate after cell removal

I have a formula cell C4 that needs to recalculate after I enter a value in another cell C2. but the C4 keeps getting cached and keeps returning old cached value.
I have asked this question multiple times on SO but I am not getting any help. I am trying every thing that I can. Here is what I found on msdn site.
With the methods from the previous code listing in place, generating
the report is now a process of getting the portfolio data and
repeatedly calling UpdateValue to create the report. Indeed, if you
add the necessary code to do this, things seem to work fine except for
one problem - any cell that contains a formula that refers to a cell
whose value was changed via Open XML manipulation does not show the
correct result. This is because Excel caches the result of a formula
within the cell. Because Excel thinks it has the correct value cached,
it does not recalculate the cell. Even if you have auto calculation
turned on or if you press F9 to force a manual recalculation, Excel
does not recalculate the cell. The solution to this is to remove the
cached value from these cells so that Excel recalculates the value as
soon as the file is opened in Excel. Add the RemoveCellValue method
shown in the following example to the PortfolioReport class to provide
this functionality.
Based on above MSDN explanation. I have tried putting the removing the code before I update the cell. After I update the cell. Before I read the formula cell, after I read the formula cell but I keep getting the following error after I read the formula cell.
System.NullReferenceException: Object reference not set to an instance
of an object.
Here is my code...
string filename = Server.MapPath("/") + "MyExcelData.xlsx";
using (SpreadsheetDocument document = SpreadsheetDocument.Open(filename, true))
{
Sheet sheet = document.WorkbookPart.Workbook.Descendants<Sheet>().SingleOrDefault(s => s.Name == "myRange1");
if (sheet == null)
{
throw new ArgumentException(
String.Format("No sheet named {0} found in spreadsheet {1}", "myRange1", filename), "sheetName");
}
WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheet.Id);
Worksheet ws = worksheetPart.Worksheet; // ((WorksheetPart)(worksheetPart.GetPartById(sheet.Id))).Worksheet;
Cell cell = InsertCellInWorksheet(ws, "C4");
// If there is a cell value, remove it to force a recalculation
// on this cell.
if (cell.CellValue != null)
{
cell.CellValue.Remove();
}
// Save the worksheet.
ws.Save();
document.Close();
}
// getting 2 numbers in excel sheet, saving, and closing it.
using (SpreadsheetDocument document = SpreadsheetDocument.Open(filename, true))
{
Sheet sheet = document.WorkbookPart.Workbook.Descendants<Sheet>().SingleOrDefault(s => s.Name == "myRange1");
if (sheet == null)
{
throw new ArgumentException(
String.Format("No sheet named {0} found in spreadsheet {1}", "myRange1", filename), "sheetName");
}
WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheet.Id);
int rowIndex = int.Parse("C3".Substring(1));
Row row = worksheetPart.Worksheet.GetFirstChild<SheetData>().
Elements<Row>().FirstOrDefault(r => r.RowIndex == rowIndex);
Cell cell3 = row.Elements<Cell>().FirstOrDefault(c => "C3".Equals(c.CellReference.Value));
if (cell3 != null)
{
cell3.CellValue = new CellValue("16");
cell3.DataType = new DocumentFormat.OpenXml.EnumValue<CellValues>(CellValues.Number);
}
worksheetPart.Worksheet.Save();
document.Close();
}
// getting the result out of excel.
using (SpreadsheetDocument document = SpreadsheetDocument.Open(filename, false))
{
document.WorkbookPart.Workbook.CalculationProperties.ForceFullCalculation = true;
document.WorkbookPart.Workbook.CalculationProperties.FullCalculationOnLoad = true;
Sheet sheet = document.WorkbookPart.Workbook.Descendants<Sheet>().SingleOrDefault(s => s.Name == "myRange1");
if (sheet == null)
{
throw new ArgumentException(
String.Format("No sheet named {0} found in spreadsheet {1}", "myRange1", filename), "sheetName");
}
WorksheetPart worksheetPart = (WorksheetPart)document.WorkbookPart.GetPartById(sheet.Id);
int rowIndex = int.Parse("C4".Substring(1));
Row row = worksheetPart.Worksheet.GetFirstChild<SheetData>().
Elements<Row>().FirstOrDefault(r => r.RowIndex == rowIndex);
Cell cell = row.Elements<Cell>().FirstOrDefault(c => "C4".Equals(c.CellReference.Value));
d.Average = Convert.ToDouble(cell.CellValue.InnerText);
}
The problem seems to be that you are directly modifying an Excel data file without Excel being open. Since Excel can only track formula dependencies when its open it does not know that it needs to recalculate when you change data without Excel knowing that you have done so.
3 possible solutions are:
1) remove the calculation chain part from the file (not tested)
2) after making the changes to the file use interop/automation to open Excel and request a full calculation (or full calculation with dependency rebuild if you are also altering/creating formulas)
3) set the fullcalculationonload property to true : this should cause Excel to do a full calculation when it opens the file
I think u have deleted the cellValue of C4 ,, first u have to create the cellValue then u can perform any operation on it .

Read Excel Cell Format

I'm working on this program that will read the data in excel file and put it into our database. The program is written in Visual Studio 2010 using C#, and I'm using the NPOI library.
In the past, I was able to read the spreadsheet row by row and cell by cell to get the data, but the new format of the excel file will not allow me to do this easily. (The excel is given by another user, so I can't really make big changes to it).
There are several "tables" in one sheet (using borders and headers for each column name), and I will need to get data mainly from the tables but sometimes outside the tables too.
I was wondering if I were to read the spreadsheet row by row (which is what I'm a bit for familiar with), is there a way I can tell that I have reached a table? Is there a way I can read the "format" of the cell?
What I mean is, for example, "this cell has borders around it so starting this row is a table." or "the text in this cell is bold, so this row is the header row for this new table."
In the past I was only able to read the "text" for the spreadsheet and not the format/style. I've been searching on the internet and I can only find how to set the style for output excel but not how to read the format from input.
Any help is appreciated, thanks!
It would be better to have the various tables in your source workbook defined as named ranges with known names. Then you can get the associated area like this -
using System.IO;
using System.Windows;
using NPOI.SS.UserModel;
using NPOI.XSSF.UserModel;
// ...
using (var file = new FileStream(workbookLocation, FileMode.Open, FileAccess.Read))
{
var workbook = new XSSFWorkbook(file);
var nameInfo = workbook.GetName("TheTable");
var tableRange = nameInfo.RefersToFormula;
// Do stuff with the table
}
If you have no control over the source spreadsheet and cannot define the tables as named ranges, you can read the cell formats as you suggest. Here is an example of reading the TopBorder style -
using (var file = new FileStream(workbookLocation, FileMode.Open, FileAccess.Read))
{
var workbook = new XSSFWorkbook(file);
var sheet = workbook.GetSheetAt(0);
for (int rowNo = 0; rowNo <= sheet.LastRowNum; rowNo++)
{
var row = sheet.GetRow(rowNo);
if (row == null) // null is when the row only contains empty cells
continue;
for (int cellNo = 0; cellNo <= row.LastCellNum; cellNo++)
{
var cell = row.GetCell(cellNo);
if (cell == null) // null is when the cell is empty
continue;
var topBorderStyle = cell.CellStyle.BorderTop;
if (topBorderStyle != BorderStyle.None)
{
MessageBox.Show(string.Format("Cell row: {0} column: {1} has TopBorder: {2}", cell.Row.RowNum, cell.ColumnIndex, topBorderStyle));
}
}
}
}

Categories

Resources