will Excel UDF gets calculation upon open? - c#

My Excel 2007 is set to Auto Calculation Mode.
I have two Excel files. MyUDF (multiple cells) is used in both files.
When I open one file in Excel, I notice no MyUDF is calculated.
But when I open the other file, all MyUDFs are calculated.
So I am a little confused as when will a UDF be calculated upon open and when not?
MyUDF is a UDF in MyAddIn written in C#
Edit
The two files are open in the same instance of Excel. MyUDF is not volatile.
Thanks
Edit
I found http://social.msdn.microsoft.com/Forums/en-US/b477c05a-ae0a-470c-8ad5-482ecd05944b/xll-addin-does-not-calculate-udf-when-opening-a-workbook?forum=exceldev
It says xla will, xll, vba will not.
hmm, this does not match what I see.

Not necessarily. Something like:
Public Function MYUDF() As Date
Application.Volatile
MYUDF = Now
End Function
will be re-calculated, however something like:
Public Function MYUDF() As Date
MYUDF = Now
End Function
may not be re-calculated.

It might be a good idea to set "automatic calculation" in your workbook's Open event. Something like this inside your ThisWorkbook object (this is important!):
Private Sub Workbook_Open()
Application.Calculation = xlCalculationAutomatic
End Sub
This is just to make sure that the setting is set as you expect within your workbook to avoid relying on what calculation mode your Excel application has in its options/settings. If nothing else, at least it eliminates one possibility for why you are getting this behaviour.

Excel "helpfully" remembers where the function was called from.
With he same function in both spreadsheets, Excel may simply be waiting for the other to open so it can do the calculation. Check the formula in the spreadsheet that does not recalculate, and see if it's changed to something like 'C:\MyDocs\MyOtherSpreadsheet.xlsb'!MyUDF(A1).
If it has, search for the full spreadsheet name (including the extra characters it uses for delimiters) and replace with nothing.
If it hasn't, set the calculation to Automatic. To force a recalculation, either select Recalculate now from the ribbon, press F9, or do a search and replace, and replace all the = with exactly the same.

Related

C# reading excel and still getting data from blank cells

I have a tool I made for work. Every week there are 5-20 files for a certain process that fails and I have to find their job ids and rerun them.
I made a tool in C# that takes the names of the failed files in an Excel spreadsheet (we'll call it the Failed File Spreadsheet, or FFS if you're feeling cynical) and then cross references them with a different Excel spreadsheet that has the job ids, and displays the result in the terminal. It reads the FFS this with a fairly simple OledDbDataAdapter code:
public static DataTable GetDataFromExcel(string filename, string sheetName)
{
using(var oledb = new OleDbConnection(CONN_STR.Replace("<FILENAME>", filename).Replace("<HDR>", "no"))
{
var result = new DataSet();
new OleDbDataAdapter($"SELECT * FROM [{sheetName}]", oledb).Fill(result);
return result.Tables[0];
}
}
The tool works fine, mostly. It cross references with another excel sheet and I get my job ids and I can carry on with my task.
However there's one slight issue, and that is that, often when running the tool, when it reads from the FFS, sometimes it returns blank lines. Like if last week I had 7 files, then this week I erased those, pasted in 5 files, then my tool will show the job ids for those 5 files just fine, but also show two blanks, as if it's still reading those two extra rows from the previous week. If however I make a new blank spreadsheet in Excel, plug in my failed files and overwrite the save file, I don't have this issue at all, making me think this is an Excel issue and not a C# coding issue.
Is there a reason why, if I delete the contents of a cell, the OleDbDataAdapter would still be reading those cells? Like are there whitespace characters or other hidden characters still present after deleting contents? I mean I could fix it in the code and just say "don't write it out if the values are whitespace or null" but I want to know why blank cells are even being read at all.
This is just a minor bug and it's not stopping me from doing my work and this tool is nothing more than a personal tool to help with a weekly task. But I'd still like to know why cells that had content, but then had that content deleted, are still being read.
Excel is a little bit quirky like that. If you are manually editing your "Failed File Spreadsheet" (FFS) and as you say, you are pasting 5 rows over the existing 7 rows, then you may still read in those extra rows after the data you expect, if there is any formatting on the cells. To avoid this, in Excel select the range of cells of the whole sheet and right-click and select "Clear Contents".
To be fair, as you alluded to, I think it would be simpler just to fix it in code and skip rows in the DataTable that are empty. Or there is a SO post here which shows how to remove empty rows from a DataTable

EPPlus excel sheet with script text in a cell

I'm coming across an issue that I'm not sure there's a good answer for.
We have a bulk-insert spreadsheet template to allow people to define certain components of an online ad. They then upload the document, we process it, and set it up in the database.
Recently there was a feature request to change bulk-insert into bulk-edit; IOW, people will download an excel sheet with information about the current ad prepopulated in the fields on the sheet. They would make changes as a set, then re-upload and we'd process the changes and update the database.
The problem is, one of the pieces of information is an HTML snippet with a <script> tag, and it seems like Excel pretty much deletes that automatically, so that column is never being populated when pulling down the sheet. It makes sense, in a way; it resembles executable code and could be a serious virus threat under some conditions, but even if I specify the column as pure text (using the Style.NumberFormat = "#" in EPPlus), Excel just makes the entire piece of data go away. It also skews the columns, looks like... shifts the subsequent cells to the left by one cell.
Is there any way to (safely) make this work without requiring changes to the downloader's security settings?
I dont have time to check into this, but What if you saved the workbook as a macro workbook, to enable some of the less secure behavior within the workbook?
One other thing may be to escape the content with a single quote ' in the beginning of the cell, or wrap the entire "script" content with quotes.
What version of excel do you expect to encounter in the wild? I tested this with Excel 2013, and was able to save the following to a workbook, and parse it into a Datatable using EPP Plus 4.1.0.0:
<script type="text/javascript">$(document).ready(function() {var I =0; console.info(I+100);});</script>
'<script type="text/javascript">$(document).ready(function() {var I =0; console.info(I+100);});</script>
"<script type='text/javascript'>$(document).ready(function() {var I =0; console.info(I+100);});</script>"
Nothing fancy, just iterating each cell in the workbook, pulling in the value and converted to string:
object obj = Worksheets[WorkSheetIndex].Cells[k, l].Value;

Issue with NumberFormat in ExportAsFixedFormat

I have a table of data (calculation results) that the user should be able to export to different formats. I use Interop.Excel to prepare a table with the data and use the data and format it using visual formatting (fonts, colors etc.) and NumberFormat. Example:
cellRange.NumberFormat = "#,##0";
When I save the table as an Excel file all formatting is ok when exporting to .xlsx and .xls:
excelWorkBook.SaveAs(exportFileName, Excel.XlFileFormat.xlOpenXMLWorkbook); // for .xlsx
excelWorkBook.SaveAs(exportFileName, Excel.XlFileFormat.xlExcel8); // for .xls
I also want to give the user the possibility to export this table to .pdf and .xps from the application without having to open the Excel file. As I have prepared the tables in Interop.Excel, I tried exporting the same table to those file formats:
excelWorkBook.ExportAsFixedFormat(Excel.XlFixedFormatType.xlTypePDF,exportFileName); // for .pdf
excelWorkBook.ExportAsFixedFormat(Excel.XlFixedFormatType.xlTypeXPS,exportFileName); // for .xps
Both of these result in good documents except that all NumberFormats are lost resulting in long decimal values of doubles. This is not appropriate for the customer's summary of the data. (Colors and fonts remain as defined in .pdf and .xps.)
I have tried setting .Styleand .Styles to "Number" or the like. This does not solve the problem.
I have also tried to protect the Range of cells or the excelWorkSheet. This does not solve the problem either.
Someone suggested calling a VBA macro / sub through C# but after some looking into that, I get the impression that it's not a very straight forward (or stable) path.
I am looking for any help in resolving this issue through Interop.Excel or in another way.
lucn
After some testing it seems clear that the property I named in my comment must be set to false:
Microsoft.Office.Interop.Excel.Application.ActiveWindow.DisplayFormulas = false;
It is not evident why this influences the export to other formats such as *.pdfbut this is clearly the case and setting the .DisplayFormulas = false solves the issue.
Hope this helps somebody.

Excel c# Issue - formula not being recalculated

I am working on a document-level excel project. This is the third version.
One of the worksheet contains a list object (data fed from a database). Then there are cells contains formulas like the following
this.Range["F15"].Formula = "=COUNTIFS(HotList_ListObject[Product],E15,HotList_ListObject[Got_Interest],\"<>\")"
previously, I created the table by just drag-and-drop. then simply created a formula in the worksheets. and the formulas were recalculated as data in the listobject (HotList_ListObject above).
this time, I created the table by the code. Because Hotlist_ListObject is not on the worksheet until the application runs, I supply the formulas after creating the listobject by code.
I looked through the internet and did a couple of testings.
When I press F9, SHIFT+F9 and CTRL+ALT+F9, it doesn't recalculate.
Only when I press CTRL+SHIFT+ALT+F9, it recalculates
the explantion I found for CTRL+SHIFT+ALT+F9 is
Rechecks dependent formulas, and then calculates all formulas in all open workbooks, regardless of whether they have changed since last time or not.
It seems that because the formula is supplied in the worksheet by code, it does not create links to dependent formulas or something so it won't recalculate. (something like this, I suppose)
My users are not going to press the button every time they modify/add/delete records in the list.
what can I do to resolve this? How to tell Excel that the formulas need to recalculate every-time any thing changes in the listobject.
Thanks for any advice in advance!
Kind regards
Mark
Does setting the Calculation to Manual:
xlApp.Calculation = XlCalculation.xlCalculationManual;
xlApp.ScreenUpdating = false;
xlApp.DisplayAlerts = false;
xlApp.UserControl = false;
xlApp.EnableEvents = false;
Then populating your Hotlist_ListObject (that is not on the worksheet until the application runs and) then set calculation to Automatic:
xlApp.Calculation = XlCalculation.xlCalculationAutomatic;
xlApp.ScreenUpdating = true;
xlApp.DisplayAlerts = true;
xlApp.UserControl = true;
xlApp.EnableEvents = true;
Resolve the problem? If not could you please post some bare bones code to illustrate the issue.
Did you check the options settings? This might be reset to manual by a macro (check with macro editor using Alt+F11 for xlCalculateManual and make sure the macro is not stopped before Application.Calculation = xlCalculationAutomatic is executed to set calaculations back to automatic. Turning calculations off is an often used method to speed macros up, but when a macro is exited half-way, this manual calculation setting will stay.
Here is the manual setting.

How to return a custom object or double[,] to a cell in Excel from ExcelDna?

Ideally my UDF would return some double results, either in a form of double[,], double[] or as a custom object. I would like it to be all stored in a single cell in Excel and then use another UDF to extract them. It is similar like cache the result of a calculation and display it later on demand.
Is it possible?
One approach is to have an internal 'object store' in your Excel-DNA add-in, and then have a function that returns some kind of 'handle' to Excel, together with accessor functions that take the 'handle' and access the object as required. Cleaning up the objects you can create is a possible issue, but can be dealt with using some of the RTD features.
This discussion on the Excel-DNA group has an example of implementing this idea in F# - https://groups.google.com/group/exceldna/browse_frm/thread/138bc83923701e6d.
It certainly is possible, but it is difficult to give you a detailed answer without knowing how you are using ExcelDNA. What I mea by that is whether you are wrapping your C# methods in vba code, or are getting a handle on the Excel application in C# and writing to the workbook directly from there.
In both cases you can do what you want, but the way to do it would be slightly different. The wrapper method would also be slightly less flexible, since you have to first pass out your values to the vba UDF and then write them to the cell from there, so you will be restricted in the data type you can return (as far as I know anyway).
The way to do this would be to write the results to a specific cell, maybe on a hidden sheet, so it can't be tampered with, and then retrieve those using another UDF. You would have to hardcode the cell address, or maybe parse the sheet to find the values you want.
In case of a method returning a double[,], you would probably have to write the values to two different cells, or in one cell as text with a separator and then convert from text to double when you retrieve the cell value, something like Double.Parse(cell.value.ToString().Split(',')[0]) to get the first values (assuming that you are storing the values as a comma-separated string) or similar code in vba if you use a pure vba UDF to get the values...
If you want to do this, I think you should definitely use a hidden sheet with a well-defined structure to store your values. If you only need to store the values for the duration of the session, then I think you should store them in global variables in a vba module.
UPDATE
Since you are just writing functions, I don't think you will be able to pass out a custom object (unless you implement your own converter, convert it to text and then read it back in that way).
You pass back the double or double[,] to a variable in your UDF and write it to a cell from there. Then read it back again from that cell with any other UDF.
The rest is the same as I wrote above. If you store two values in the same cell, you will have to do that as text, so you will have to split and parse the values first in your UDF before passing them to your C# method (or you can do the parsing in the method).
In practice there should be no problem at all with what you are trying to do.

Categories

Resources