Is there a way to get 'named' cells using EPPlus? - epplus

I have an Excel file that I am populating programmatically with EPPlus.
I have tried the following:
// provides access to named ranges, does not appear to work with single cells
worksheet.Names["namedCell1"].Value = "abc123";
// provides access to cells by address
worksheet.Cells["namedCell1"].Value = "abc123";
The following does work - so I know I am at least close.
worksheet.Cells["A1"].Value = "abc123";

Actually, its a bit misleading. The Named Ranges are stored at the workBOOK level and not the workSHEET level. So if you do something like this:
[TestMethod]
public void Get_Named_Range_Test()
{
//http://stackoverflow.com/questions/30494913/is-there-a-way-to-get-named-cells-using-epplus
var existingFile = new FileInfo(#"c:\temp\NamedRange.xlsx");
using (var pck = new ExcelPackage(existingFile))
{
var wb = pck.Workbook; //Not workSHEET
var namedCell1 = wb.Names["namedCell1"];
Console.WriteLine("{{\"before\": {0}}}", namedCell1.Value);
namedCell1.Value = "abc123";
Console.WriteLine("{{\"after\": {0}}}", namedCell1.Value);
}
}
You get this in the output (using an excel file with dummy data in it):
{"before": Range1 B2}
{"after": abc123}

Related

Reading long sequence of digit as string

I'm using EPPlus to read a customer database.
From time to time in a text cell I'm reading as string, the customer wrote a long sequence of digit
My code read it as exponential format.
Is there a way to force the reading as string?
Here's the code snippet I'm using
using (ExcelPackage xlPackage = new ExcelPackage(new FileInfo(xlsFile))) {
var myWorksheet = xlPackage.Workbook.Worksheets.First();
while (!string.IsNullOrEmpty(myWorksheet.Cells[rowNum, 1].GetValue<string>()))
{
var cell = myWorksheet.Cells[rowNum, 20];
var idDoc = cell.GetValue<string>(),
// do something with idDoc
rowNum += 1;
}
}
when the cell contains, let's say 1790002099190700, idDoc is "1,7900020991907E+15"
What you are seeing make sense as excel will store the value as a double like any other numeric value.
It looks like you are exporting from a database to excel. I would assume that when exported there is no formatting set in Excel in which case using the .Text value of the cell object simply fall back to "General" in excel.
Say you have this:
So, what you end up with is this:
[TestMethod]
public void Cell_Digits_As_String()
{
//https://stackoverflow.com/questions/58058900/reading-long-sequence-of-digit-as-string
var fi = new FileInfo(#"c:\temp\Cell_Digits_As_String.xlsx");
using (var package = new ExcelPackage(fi))
{
var workbook = package.Workbook;
var worksheet = workbook.Worksheets.First();
var valCell = worksheet.Cells[1, 1];
var valText = valCell.Text; //Applies "General" unless otherwise specified
var valValue = valCell.Value; //As a BOXED double
var valString = valCell.GetValue<string>(); //Falls back to ChangeType
Console.WriteLine($"Value as text: {valText} ({valText.GetType()})");
Console.WriteLine($" Same as: {((double)valValue).ToString("0.#####", new CultureInfo("es-US"))}");
Console.WriteLine($"Value as value: {valValue} ({valValue.GetType()})");
Console.WriteLine($" Same as: {valValue.ToString()}");
Console.WriteLine($"Value as string: {valString} ({valString.GetType()})");
Console.WriteLine($" Same as: {Convert.ChangeType(valValue, typeof(double)).ToString()}");
}
}
Which shows this in the out:
Value as text: 1790002099190700 (System.String)
Same as: 1790002099190700
Value as value: 1.7900020991907E+15 (System.Double)
Same as: 1.7900020991907E+15
Value as string: 1.7900020991907E+15 (System.String)
Same as: 1.7900020991907E+15
So, it would seem that using .Text is the most convenient to get what you want. But if you are concerned about the formatting being altered in any way or just want to be absolutely sure, just do:
try
{
((double)valCell.Value).ToString("0.#");
}
catch (Exception ex)
{
//Handle it...
}

Workbook cell style in POI/NPOI doesn't work properly with multiple styles in workbook

I'm running into strange problem with .Net version of POI library for Excel Spreadsheets. I'm rewriting from text files to Excel 97-2003 documents and I'm like to add some formatting programmatically depend on some values gather at the begging of the program.
At the beginning, in the same method where I was creating a new cell from given value I was creating also a new Workbook CellStyle which was wrong, because I was running out of the styles very quickly (or I was just thought it was the cause of the problem).
Constructor of the class responsible for Excel Workbook:
public OldExcelWriter(TextWriter logger) : base(logger)
{
_workbook = new HSSFWorkbook();
_sheetData = _workbook.CreateSheet("sheet1");
_creationHelper = _workbook.GetCreationHelper();
}
Method that is calling all the chains of operations:
public void Write(string path, Data data)
{
FillSpreadSheetWithData(data, _sheetData);
SaveSpreadSheet(_workbook, path);
}
Long story short, in FillSpreadSheetWithData I have method for creating a row inside which I'm have a loop for each cell, so basically I'm iterating thru every column, passing IRow references to a row, column value, index and formatting information like this:
for (int j = 0; j < column.Count; j++)
{
CreateCell(row, column[j], j, data.Formatting[j]);
}
and while creating a new styles (for first shot I was trying to pass some date time values) I had situation like this in my rewrited Excel: screenshot of excel workbook
So formatting was passed correctly (also Horizontal Aligment etc.) but it get ugly after 15th row (always the same amount).
DateTime dataCell = DateTime.MaxValue;
var cell = row.CreateCell(columnIndex);
_cellStyle = _workbook.CreateCellStyle();
switch (format.Type)
{
case DataType.Date:
_cellStyle.DataFormat = _creationHelper.CreateDataFormat().GetFormat("m/dd/yyyy");
if (value.Replace("\n", "") != string.Empty)
{
dataCell = DateTime.ParseExact(value.Replace("\n", ""), "m/dd/yyyy",
System.Globalization.CultureInfo.InvariantCulture);
}
break;
}
switch (format.HorizontalAlignment)
{
case Enums.HorizontalAlignment.Left:
_cellStyle.Alignment = HorizontalAlignment.LEFT;
break;
case Enums.HorizontalAlignment.Center:
_cellStyle.Alignment = HorizontalAlignment.CENTER;
break;
}
if (dataCell != DateTime.MaxValue)
{
cell.CellStyle = _cellStyle;
cell.SetCellValue(dataCell);
dataCell = DateTime.MaxValue;
}
else
{
cell.CellStyle = _cellStyle;
cell.SetCellValue(value);
}
(It's not the cleanest code but I will don refactor after getting this work).
After running into this issue I thought that maybe I will create _cellStyle variable in the constructor and only change it's value depends on the case, because it's assigned to the new cell anyway and I see while debugging that object values are correct.
But after creating everything, it won't get any better. Styles was override by the last value of the style, and dates are spoiled also, but later: screnshoot of excel workbook after creating one instance of cell style
I'm running out of ideas, maybe I should create every combination of the cell styles (I'm using only few data formats and alignments) but before I will do that (because I'm running out of easy options right now) I wonder what you guys think that should be done here.
cell format is set to custom with date type
I am using this code to create my custom style and format. Its for XSSF Format of excel sheet. but it will work for HSSF format with some modification.
XSSFFont defaultFont = (XSSFFont)workbook.CreateFont();
defaultFont.FontHeightInPoints = (short)10;
defaultFont.FontName = "Arial";
defaultFont.Color = IndexedColors.Black.Index;
defaultFont.IsBold = false;
defaultFont.IsItalic = false;
XSSFCellStyle dateCellStyle = (XSSFCellStyle)workbook.CreateCellStyle();
XSSFDataFormat dateDataFormat = (XSSFDataFormat)workbook.CreateDataFormat();
dateCellStyle.SetDataFormat(dateDataFormat.GetFormat("m/d/yy h:mm")); //Replace format by m/dd/yyyy. try similar approach for phone number etc.
dateCellStyle.FillBackgroundColor = IndexedColors.LightYellow.Index;
//dateCellStyle.FillPattern = FillPattern.NoFill;
dateCellStyle.FillForegroundColor = IndexedColors.LightTurquoise.Index;
dateCellStyle.FillPattern = FillPattern.SolidForeground;
dateCellStyle.Alignment = HorizontalAlignment.Left;
dateCellStyle.VerticalAlignment = VerticalAlignment.Top;
dateCellStyle.BorderBottom = BorderStyle.Thin;
dateCellStyle.BorderTop = BorderStyle.Thin;
dateCellStyle.BorderLeft = BorderStyle.Thin;
dateCellStyle.BorderRight = BorderStyle.Thin;
dateCellStyle.SetFont(defaultFont);
//Apply your style to column
_sheetData.SetDefaultColumnStyle(columnIndex, dateCellStyle);
// Or you can also apply style cell wise like
var row = _sheetData.CreateRow(0);
for (int cellIndex = 0;cellIndex < TotalHeaderCount;cellIndex++)
{
row.Cells[cellIndex].CellStyle = dateCellStyle;
}

Setting several "setValue" at once

I have some cells (that are non-adjacenet). Each of these has a range name in the form "rLampnn" as below.
ss.getRangeByName("rLamp20").setValue(e.range.getValue());
ss.getRangeByName("rLamp19").setValue(e.range.getValue());
ss.getRangeByName("rLamp18").setValue(e.range.getValue());
I want to put the same value into several of them at once. (Each of them then has a conditional format which changes the cell colour depending on what was entered into them).
Is there a more efficient way (i.e. quicker) of setting the same value into a group of these cells rather than individual calls like above?
If you have many of them you could loop .setValue() using the nn index in the named ranges:
var fName = 'rLamp';
var howManyNamedRanges = 20;
// Assuming the first NamedRange is rLamp0
for (var i=0;i<howManyNamedRanges;i++) {
ss.getRangeByName(fName+i).setValue(e.range.getValue());
}
If the first named ranges is 1 or else you could change it to:
var fName = 'rLamp';
var firstNamedRange = 4;
var lastNamedRange = 20;
// Assuming the first NamedRange is rLamp[n]
for (var i=firstNamedRange;i<=lastNamedRange;i++) {
ss.getRangeByName(fName+i).setValue(e.range.getValue());
}

How to save Excel Table as a Picture using vb.net?

I'm trying to save tables from excel sheets as pictures. Is there a way to just put that table on the clipboard and save it? This is what I've got so far but the library referenced is not there?
Thank you in advance!
-Rueben Ramirez
Public Sub extract_excelTable(ByRef data_file As String, ByRef app1 As excel.Application, ByRef sheet_name As String)
'defining new app to prevent out of scope open applications
Dim temp_app As excel.Application = app1
Dim workbook As excel.Workbook = temp_app.Workbooks.Open(Path.GetFullPath(data_file))
temp_app.Visible = False
For Each temp_table As excel.DataTable In workbook.Worksheets(sheet_name)
temp_table.Select()
'temp_app.Selection.CopyAsPicture?
Next
End Sub
I'm not going to write any code here, but I will outline a solution for you that will work. Note that this will not reproduce the formatting of the excel document, just simply get the data from it, and put it on an image in the same column/row order as the excel file.
STEP 1:
My solution to this problem would be to read the data from the excel file using an OLEDB connection as outlined in the second example of this post: Reading values from an Excel File
Alternatively, you may need to open the document in excel and re-save it as a CSV if it's too large to fit in your computer's memory. I have some code that reads a CSV into a string list in C# that may help you:
static void Main(string[] args)
{
string Path = "C:/File.csv";
System.IO.StreamReader reader = new System.IO.StreamReader(Path);
//Ignore the header line
reader.ReadLine();
string[] vals;
while (!reader.EndOfStream)
{
ReadText = reader.ReadLine();
vals = SplitLine(ReadText);
//Do some work here
}
}
private static string[] SplitLine(string Line)
{
string[] vals = new string[42];
string Temp = Line;
for (int i = 0; i < 42; i++)
{
if (Temp.Contains(","))
{
if (Temp.Substring(0, Temp.IndexOf(",")).Contains("\""))
{
vals[i] = Temp.Substring(1, Temp.IndexOf("\",", 1) - 1);
Temp = Temp.Substring(Temp.IndexOf("\",", 1) + 2);
}
else {
vals[i] = Temp.Substring(0, Temp.IndexOf(","));
Temp = Temp.Substring(Temp.IndexOf(",") + 1);
}
}
else
{
vals[i] = Temp.Trim();
}
}
return vals;
}
STEP 2:
Create a bitmap object to create an image, then use a for loop to draw all of the data from the excel document onto the image. This post had an example of using the drawstring method to do so: how do i add text to image in c# or vb.net

Autofitting column in combination with setting numberformat will autofit using unformatted text as measurement

When I use EPPlus to autofit a column that is formatted as a date string, the autofit mechanism is using the unformatted string as measurement for how wide the column should become.
Is it a bug or did I do something wrong?
Code
sheet.Column(2).Style.Numberformat.Format = "yyyy-MM-dd hh:mm";
sheet.Cells.AutoFitColumns();
Result:
widening the second column in excel
Autofit using no formatting, notice that the second column is having the same width as the supposed-to-autofit column in the first picture.
For completion, here is the result when no autofit is used
It could be your font settings either in your code or globally in excel. Try running this test (I am posting this as an answer since I cannot fit it in a comment):
[TestMethod]
public void Auto_Col_Fomat_Test()
{
//Throw in some data
var datatable = new DataTable("tblData");
datatable.Columns.AddRange(new[]
{
new DataColumn("Col1", typeof (int)), new DataColumn("Col2", typeof (DateTime)), new DataColumn("Col3", typeof (object))
});
for (var i = 0; i < 10; i++)
{
var row = datatable.NewRow();
row[0] = i; row[1] = DateTime.Now.AddDays(i); row[2] = Path.GetRandomFileName();
datatable.Rows.Add(row);
}
//Create a test file
var fi = new FileInfo(#"c:\temp\Auto_Col_Fomat.xlsx");
if (fi.Exists)
fi.Delete();
using (var pck = new ExcelPackage(fi))
{
var workbook = pck.Workbook;
var sheet = workbook.Worksheets.Add("Sheet1");
sheet.Cells.LoadFromDataTable(datatable, true);
sheet.Column(2).Style.Numberformat.Format = "yyyy-MM-dd hh:mm";
sheet.Cells.AutoFitColumns();
pck.Save();
}
}
If this shows the same thing you may have changed your default excel font or zoom which means you may have to set the font in code to Body Font size 11 (at least that was 2013 uses). If it doesnt show post more of your code.
I had the same issue.
Here is my work around:
First call AutoFitColumns, then add some padding to the column that has a special format:
cells[sheet.Dimension.Address].AutoFitColumns();
sheet.Column(2).Width *= 1.25;