How to read the value of range that is Merged with EPPlus?
Lets say the range "G15:G18" is merged. How do I retrieve the text inside that range?
I've tried this, but without success:
string txt = ws.Cells["G15:G18"].Value.ToString();
Thanks.
Looking better at the issue, I finally understood that what I was doing was actually bringing a collection of results, where only the first item has a value.
So, basically, this code:
string txt = ws.Cells["G15:G18"].Value.ToString();
would return an array like with the text for all the cells in the range.
But except for the first cell in the array, all cells are empty. Only the first cell hold the Value for the whole range.
What I did is as simple as this:
string val = ws.Cells["G15:G18"].First().Value.ToString();
It worked fine.
Unless I missed the boat, I think it might be even easier than you think... just look for the value for the first cell in the range:
string txt = ws.Cells["G15"].Value.ToString();
Also, if you know it's text or just want the text representation of the cell, you can use the Text property:
string txt = ws.Cells["G15"].Text;
I think this concept transcends EPPlus also -- you can reference it in Excel formulas, and I believe it works this way in Interop as well.
Related
I have an ETL that's saving data to an Excel file. The issue is that the decimals are not being written out for integers. Example:
14.00
is being written out as
14
My code for writing out that line is
loWorksheet.Cells[liRowNum, 5] = lcAmount.ToString("0.00");
When I step through the code, it shows as 14.00, but on the Excel file it is not retaining the decimal places. Is this something that can be fixed in my code or is this an Excel issue? Any suggestions?
I'm quite sure you have to set format for your cells. I can't check right now, but it will be something like
xlYourRange.NumberFormat = "0.00";
You can check this question Set data type like number, text and date in excel column using Microsoft.Office.Interop.Excel in c#
If you really want the data to be displayed literally the way it is in the source file, you have to deal with trade-offs. The simplest way is to format the data as text. You can do this a cell at a time or for entire columns:
loWorksheet.Columns["A:E"].NumberFormat = "#";
The trade-off is it's just text at this point. You can't add, sum, average, whatever.
On the other hands, if your data looks like this:
4.0
4.00
4.000
You can't really keep it as numbers and expect to retain the original format without doing some funny business.
If it's consistently two decimal places, and you know it's going to be, then I agree with #RenatZamaletdinov's solution.
And you might want to consider other strings and what Excel might to do them
0000123 becomes 123
10/23 will probably render as a date, depending on your localization
12345678901234567890 will render as scientific notation probably
These are all avoided if you make the numeric format text (#), but again without knowing what you plan to do with the data, it's hard to say if this is the correct approach.
Wrap lcAmount.ToString("0.00");in a pair of quotes and put an equal sign in front of it. This will prevent excel from overriding the format.
loWorksheet.Cells[liRowNum, 5] = "=" + '"' lcAmount.ToString("0.00") + '"';
My C# code manipulates Excel Ranges using Microsoft.Office.Interop.Excel library. I need to assign a Formula Array to a selected Range. I've tried a variety of methods recommended online, including Microsoft recommendations, but so far was unable to make it work properly.
I observe 2 issues:
Issue 1.
Assignment looks fine on surface: it does not fail, cell objects in the range show .ArrayFormula property assigned, on the spreadsheet formula in every cell appears in curly brackets. However, the Formula Array is actually disjointed: each cell in the range can be changed separately, which normal Formula Array would not permit. It behaves as if every cell had its own, single-cell Formula Array, independent from others. Regardless of my best efforts, this is ALWAYS the case.
Is there actually a properly working solution for this issue?
Issue 2.
My Array Formula contains a reference to another Range (Range A), which I need to refer to in R1C1 style. I need Array Formula in every cell in the target Range point to the same Range A. Somehow I always end up with every cell in target Range having its own version of the formula, referring to shifted "Range A" area. How do I make the reference stay in place, regardless of a cell?
N.B. You may assume that Issue 2 is causing Issue 1, but this is not the case: for example, when array formula is simple, like "=SIN(1)", the Issue 1 still occurs.
I would really appreciate any WORKING suggestions. Thanks a lot in advance.
No one seemed interested, however I found a solution and will answer to my own question.
Apparently, assignment of an Excel Array Formula within C# code works only if the formula is in A1 style, not in R1C1 style. In my case, I was starting with a R1C1-style formula, so it required conversion to A1 style. This is achieved by assigning the original R1C1-style formula to the top left cell of the target range:
topLeftCell.Formula = myR1C1Formula;
// topLeftCell.FormulaR1C1 = myR1C1Formula also works
Assignment to that particular cell will ensure that A1-style formula contains correct references. Get back the converted formula as a string:
string formulaA1 = topLeftCell.Formula;
Get reference to the whole target range by rezising the top left cell:
Excel.Range newArrayRange = topLeftCell.Resize[height, width];
Resize operation must precede the following assignment. Finally, assign the A1-style formula to the FormulaArray property of the whole target range:
newArrayRange.FormulaArray = formulaA1;
This works perfectly without issues or side-effects.
Which would be potentially a best way to enumerate or iterate or simply look for empty cells or cells with specific data structure in Excel, and later once you find it do some processing on it.
I tired Range, Value, Value2, etc but it takes fairly long time when Excel Sheet is considerably larger. I believe there must be some other efficient way.
It would be nice, if you can show some example snippet.
The answer is relativley simple: get the array in one batch from excel (search SO for a how to) - test the values of the erray for empty cells and then acess only the empty cells in excel.
It is somewhat cumbersome, but the fastes way because iterating each cell is vastly slower than simply getting all data in a batch.
To find blank cells, use the .SpecialCells method of a range object.
http://msdn.microsoft.com/en-us/library/microsoft.office.interop.excel.range.specialcells(v=office.11).aspx
The .specialCells method returns a range object of the matching criteria (i.e., xlCellTypeVisible, xlCellTypeBlanks, etc.). You can then iterate of this range to perform your formatting, etc.
Update I'm not a C# programmer, but I can show you how I would do this in VBA. Assuming interop exposes most/all of the same methods and functionality, you should hopefully be able to translate this for your purposes.
Sub ColorVisibles()
Dim rng As Range
Dim rngBlanks As Range
Dim blanksExist As Boolean
'define your range
Set rng = Range("A1:AA300")
'check to make sure there are blank cells in the range:
blanksExist = Application.WorksheetFunction.CountBlank(rng) > 0
If blanksExist Then
Set rngBlanks = rng.SpecialCells(xlCellTypeBlanks)
rngBlanks.Interior.Color = vbYellow
Else:
MsgBox "No blank cells exist in the specified range.", vbInformation
End If
End Sub
I'm using code lines similar to the one below several times throughout the loop. It works all fine EXCEPT it doesn't follow the "no two dot rule", right?
wksheet.Cells(cell.Row, "J").Value
I can store cell.Row as an int, but where to go from there? Is there a function that lets me pass row number and column letter and get the value of that particular cell while still following the rule?
It would be a pain to declare and then set the range variable every time I want to get a particular cell's value inside the loop.
How do I properly clean up Excel interop objects?
^this link explains no two dot rule.
I guess you could break it down
var row = cell.Row;
var cell = wksheet.Cells(row, "J");
var value = cell.Value;
I've been googling and searching on the site for the answer, but I couldn't find a solution - everywhere people mostly discuss how to add new number format to the document and apply it.
What I need is to get the cell value as a string with applied formatting - i.e. same string as would be displayed by Excel.
I already figured that there's no easy way or built-in function which would return the readymade formatted value for a cell.
So it seems to me that to get the value I need to do two things:
1. Get the format string.
2. Format the cell value using this string.
But I have problems with both steps.
One can easily get CellFormat instance which would contain NumberFormatId:
CellFormat cellFormat = (CellFormat) document.WorkbookPart.WorkbookStylesPart.Stylesheet.CellFormats.ElementAt(cell.StyleIndex);
But how to get the format string with this NumberFormatId, if the id corresponds to one of standard predefined formats? (i.e. is below 160) They are not in the spreadsheet document and I can't believe that they should be hardcoded in the application.
Also, once the format string is somehow obtained, how to apply it to the cell value? So far I understand, the code should check the type of the cell value and if is Number - convert it to string using the format string.
I found this page which mentions using Microsoft.Office.Excel.Interop, but I would prefer to stay with OpenXML SDK only.
Overall, I'm very surprised that it's so difficult to find a definitive answer to this question on the Web as I thought that this would be something which many developers need in their daily work.
Men, this is a hard one... I will be adding here things that i found that could be worth..
First is to get the numbering format of the cell (once you have the CellFormat:
string format = excel.WorkbookPart.WorkbookStylesPart.Stylesheet.NumberingFormats.Elements<NumberingFormat>()
.Where(i => i.NumberFormatId.ToString() == cellFormat.NumberFormatId.ToString())
.First().FormatCode;
For more information about this you can go to: NumberingFormats
Im trying to find out how to apply this format to the cell.CellValue property... I think thats the way you have to go!
Ok, reading the ClosedXml code (its open source), seems to be easy to get the format.
Simply convert the value text to its type (int, double, etc) and call the ToString method passing the format. I was trying do that with the String.Format and didnt work. Ive tested the ToString and it works, but something still missing.
I recommend to you to look at this class and get the code from the method GetFormattedString() as #El G tell in his comment.
Bassicaly you will have to add something like this:
double d = double.Parse(cell.CellValue.InnerText);
string val = d.ToString(format);
Hope it helps you...
If you want to take cell value with applied formatting, same as displayed in Excel, use .Text property of Cell object. Like this:
String formattedValue = cell.Text