Office Open XML - Target Cell by its content - c#

How to target Cell if I know its content (there are no duplicates in the xlsx document) using Office Open XML?
I mean I have xlsx sheet (template) and somewhere in it placed my "variable". For example "<<_time>>". I want to find that element (by "variable" name) and change the cell value (current time in this case).
Basic code:
FileInfo newFile = new FileInfo(#"...");
FileInfo template = new FileInfo(#"...");
using (ExcelPackage xlPackage = new ExcelPackage(newFile, template))
{
ExcelWorksheet worksheet = xlPackage.Workbook.Worksheets.First();
//need target Cell by it's value (must use for-loop?)
//worksheet.Cells[...].Value = "...";
xlPackage.Save();
}

Ok, I solved it by classic loop.
var start = worksheet.Dimension.Start;
var end = worksheet.Dimension.End;
for (int row = start.Row; row <= end.Row; row++)
{
for (int col = start.Column; col <= end.Column; col++)
{
string cellValue = worksheet.Cells[row, col].Text.ToString();
if (cellValue == "<<_time>>")
{
worksheet.Cells[row, col].Value = "..";
}
}
}

Related

Filter specific rows of worksheet C#

I'm currently trying to get specific rows of an Excel file in my code.
I get the data of my Excel file with this code:
FileInfo existingFile = new FileInfo(local_in_file_path);
using (ExcelPackage package = new ExcelPackage(existingFile))
{
ExcelWorksheet worksheet = package.Workbook.Worksheets[1];
int colCount = worksheet.Dimension.End.Column; //get Column Count
int rowCount = worksheet.Dimension.End.Row; //get row count
List<string> testlist = new List<string>();
List<string> articlelist = new List<string>();
for (int row = 1; row <= rowCount; row++)
{
for (int col = 1; col <= colCount; col++)
{
testlist.Add(worksheet.Cells[row, col].Value?.ToString().Trim());
foreach (var i in testlist)
{
if (articlelist.Contains(i))
{
continue;
}
else
{
articlelist.Add(i);
}
}
}
}
foreach (var article in articlelist)
{
var rows = worksheet.Row().Where(n => n = article); //doesnt work
}
In the foreach loop I want all rows, in which the specific article occurs. How can I do this?
Be careful because when you add something to testlist you are picking only 1 cell everytime (so if your excel file is structured like "1 row has 'article name' , 'description' ecc you are running through every col in every row so it's pretty inefficient, if you could only provide an example of your excel file we can try to help, and does that foreach create an exception or something else?

Iterating and adding all column names to a ComboBox using EPPlus

I need to add the column names within a sheet to a combobox
I have tried the following
var pck = new OfficeOpenXml.ExcelPackage();
pck.Load(new System.IO.FileInfo("test.xlsx").OpenRead());
var ws = pck.Workbook.Worksheets[1];
int totalCols = ws.Dimension.End.Column;
for (int i = 1; i <= totalCols; i++)
{
comboBox1.Items.Add( (ws.Column(i).ToString()));
}
}
But this produces a Null Reference Exception.
Why is that happening?
Ensure that you're loading the package correctly and selecting the values correctly:
// Select workbook
var fileInfo = new FileInfo(#"yourfile.xlsx");
// Load workbook
using (var package = new ExcelPackage(fileInfo)) {
// Itterate through workbook sheets
foreach (var sheet in package.Workbook.Worksheets){
// Itterate through each column until final column
for (int i = 1; i <= sheet.Dimension.End.Column; i++) {
comboBox1.Items.Add(sheet.Cells[1, i].Text);
}
}
}
This runs correctly in a new workbook with two sheets and values in the columns of each sheet.

Force EPPLUS to read as text

I'm developping an application to read xlsx files, do some validation and insert into database. Unfortunatelly when I try to read columns marked as numeric (fe with EAN-13 codes) I get miniumum value of an int.
The user doesn't see this because Excel displays it properly.
How can I make it read the file as plain text? I know I can use OLEBD for it, but I also need to edit the file dynamically, so epplus ExcelPackage is the best choice.
Here is code im using:
FileInfo file = new FileInfo(path);
MainExcel = new OfficeOpenXml.ExcelPackage(file);
{
var ws = MainExcel.Workbook.Worksheets.First();
DataTable tbl = new DataTable();
for (var rowNum = 1; rowNum <= ws.Dimension.End.Row; rowNum++) //currently loading all file
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
var row = tbl.NewRow();
foreach (var cell in wsRow)
{
row[cell.Start.Column - 1] = cell.Text;
}
tbl.Rows.Add(row);
}
}
and that's how I enumerate columns
foreach (var firstRowCell in ws.Cells[3, 1, 3, ws.Dimension.End.Column])
{
System.Type typeString = System.Type.GetType("System.String") ;
tbl.Columns.Add( firstRowCell.Text , typeString );
}
For people whom it might concern, here is the file (works also for non google users):
https://drive.google.com/open?id=0B3kIzUcpOx-iMC1iY0VoLS1kU3M&authuser=0
I noticed that ExcelRange.value property is an array which contains all of the objects unformatted. But once you iterate over cells in ExcelRange and request cell.Text property, it has already been processed. Trying to modify ConditionalFormatting and DataValidation in ExcelRange does not help (f.e. AddContainsText()) - #EDIT--> Neither for an entire sheet :-(
I'd prefer NOT to cast ExcelRange.Value as Array, it's ugly and very conditional.
Apparently this is the solution (not complete code though, you have to add columns to datatable). I couldn't find the format string which specifies 'no formatting' in Epplus, but here you have it.
var ws = MainExcel.Workbook.Worksheets.First();
DataTable tbl = new DataTable();
for (var rowNum = 1; rowNum <= ws.Dimension.End.Row; rowNum++)
{
var wsRow = ws.Cells[rowNum, 1, rowNum, ws.Dimension.End.Column];
var array = wsRow.Value as object[,];
var row = tbl.NewRow();
int hhh =0;
foreach (var cell in wsRow)
{
cell.Style.Numberformat.Format = "#";
row[cell.Start.Column - 1] = cell.Text;
}
tbl.Rows.Add(row);
}
The cells in your file are custom-formatted as a fraction. Have you done this on purpose?
Anyway, if you want to keep this format, you can alternatively use cell.Value or cell.RichText.Text to get your 13-digit number.
Hope this helps.

NPOI apply font to entire row of cells

I'm using NPOI to export my data to excel. The problem is I found it really hard for any kind of graphical changes.
This is the method I'm using now to apply bold font to my cells.
//Create new Excel workbook
var workbook = new HSSFWorkbook();
//Create new Excel sheet
var sheet = workbook.CreateSheet();
//Create a header row
var headerRow = sheet.CreateRow(0);
var boldFont = workbook.CreateFont();
boldFont.FontHeightInPoints = 11;
boldFont.FontName = "Calibri";
boldFont.Boldweight = (short)NPOI.SS.UserModel.FontBoldWeight.Bold;
int cellCounter = 0;
//day
var cell = headerRow.CreateCell(cellCounter++);
cell.SetCellValue("Day");
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(boldFont);
//month
cell = headerRow.CreateCell(cellCounter++);
cell.SetCellValue("Month");
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(boldFont);
//year
cell = headerRow.CreateCell(cellCounter++);
cell.SetCellValue("Year");
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(boldFont);
//machine name
cell = headerRow.CreateCell(cellCounter++);
cell.SetCellValue("Machine unique name");
cell.CellStyle = workbook.CreateCellStyle();
cell.CellStyle.SetFont(boldFont); //and so on
Is there a ,,cleaner" way to do this ? Now i have to manually add font for individual cells. I've tried many ways to do this on the internet and nothing seems to be working. Do you have a tested way to apply style to specific column or row ?
OffTopic: If not can you provide me with some good open source libraries with decent documentation and support that allow excel export (learning new dll is a pain but... :) what can you do)?
I'm doing something similar and modified my take on it closer for your use:
private string[] columnHeaders =
{
"Day",
"Month",
"Year",
"Machine Unique Name"
}
private void buildSheet(HSSFWorkbook wb, DataTable data, string sheetName)
{
var cHelp = wb.GetCreationHelper();
var sheet = wb.CreateSheet(sheetName);
HSSFFont hFont = (HSSFFont)wb.CreateFont();
hFont.FontHeightInPoints = 11;
hFont.FontName = "Calibri";
hFont.Boldweight = (short)NPOI.SS.UserModel.FontBoldWeight.Bold;
HSSFCellStyle hStyle = (HSSFCellStyle)wb.CreateCellStyle();
hStyle.SetFont(hFont);
IRow headerRow = sheet.CreateRow(1);
int cellCount = 1;
foreach (string str in columnHeaders)
{
HSSFCell cell = (HSSFCell)headerRow.CreateCell(cellCount);
cell.SetCellValue(cHelp.CreateRichTextString((str)));
cell.CellStyle = hStyle;
cellCount += 1;
}
This iterates over however many headers you want starting at the second cell (cellCount = 1) second row (sheet.CreateRow(1)).

EPPlus, Find and set the value for a Named Range

I've been pulling my hair out trying to set the value of a named range (in this case, a single named cell) using the ExcelPackage (3.0.1) library, it should be a simple as this:
ExcelNamedRange er = xlPackage.Workbook.Names["Customer"];
er.Value = "Foo Bar";
I'm obviously doing it wrong - has anyone got an example I can follow
Thanks
I looked for ExcelPackage documentation to see what type Names[] collection returns and found that documentatios will come soon, or at least that is what they said back in 2007.
I suggest you use EPPlus wich is a excel library (xlsx only) that have worked great to me.
official link
Now, to set a value for each cell in a named range:
ExcelWorksheet sheet = _openXmlPackage.Workbook.Worksheets["SheetName"];
using (ExcelNamedRange namedRange = sheet.Names["RangeName"])
{
for (int rowIndex = Start.Row; rowIndex <= namedRange.End.Row; rowIndex++)
{
for (int columnIndex = namedRange.Start.Column; columnIndex <= namedRange.End.Column; columnIndex++)
{
sheet.Cells[rowIndex, columnIndex].Value = "no more hair pulling";
}
}
}
I had to put in a work around using a cell value instead.
using (ExcelPackage xlPackage = new ExcelPackage(newFile))
{
foreach (ExcelWorksheet worksheet in xlPackage.Workbook.Worksheets)
{
var dimension = worksheet.Dimension;
if (dimension == null) { continue; }
var cells = from row in Enumerable.Range(dimension.Start.Row, dimension.End.Row)
from column in Enumerable.Range(dimension.Start.Column, dimension.End.Column)
//where worksheet.Cells[row, column].Value.ToString() != String.Empty
select worksheet.Cells[row, column];
try
{
foreach (var excelCell in cells)
{
try
{
if (excelCell.Value.ToString().Equals("[Customer]")) { excelCell.Value = "Customer Name"; }
}
catch (Exception) { }
}
}
catch (Exception a) { Console.WriteLine(a.Message); }
}

Categories