I have an excel function that get's data from the internet. The problem is that the function takes a long time to execute and it slows down everything.
It will be amazing if I can change the value of the cell without changing its formula! So if I call the function =GetNumOfEmployee() that returns 0 imediately and then from my addin when I get the result I can replace the value of that cell with 100 for example. If I do that the fomula gets lost and I do not want that to happen.
What I did in order to preserve the formula was to change the formatting of the cell by doing:
this.Application.ActiveCell.NumberFormat = 5;
if the active cell had a 0, then that line of code will replace the value to a 5 which is very cool. I get to preserve the formula and I have a new value.
The problem with that approach is that I get a lot of calculations and every time I write the line:
this.Application.ActiveCell.NumberFormat = 1234;
excel saves that formating at:
and very soon I reach the maximum number of formatings that excel enables. In 1 minute that list has about 500 formats and soon I am not able to delete them. If I programatically delete them excel acts kind of slow and I get the windows spining mouse icon every time I delete a format.
So in short I will like to replace the value of a cell without changing its' formula from my addin once I have the result that I need back. Should I place the value to the right of the cell?
Related
I have an Excel file that contains lots of data, and I'm making a program that reads the excel file, does some statistics, and prints the findings in console.
I need to count the occurrences of a specific string, in a specific column, and save the result to a variable in code.
I've thought of using excel's COUNTIF() formula, but it seems like I have to put the formula in a cell, to read the result, and therefore cant just assign a variable to it's result.
How can I do the same thing as COUNTIF() without modifying the file?
I have an XLL which returns an LPXLOPER result of type 2D array for a Range with FormulaArray.
Things go happily <1s update until I hit about size 50x200. At that point, Excel gets stuck blinking "Ready (pretty Excel graphic)" and "Filling cells (empty progress bar)" at 100% usage of 1 core which goes on for less than half a minute before returning values.
At 100x100 it takes 8-10 minutes.
At 200x100 I'm still waiting for it to return.
The code is identical in all cases. I step through the VB and it hangs on calling RUN(...) to populate the data array. No further code is executed. I put breakpoints in my XLL and it doesn't hit any of them. I break into Excel and it's doing Excel stuff in EXCEL.EXE or in libraries I didn't even know existed.
Anyone know (a) what Excel is doing when it says Ready / Filling Cells even though it is obviously NOT ready, and (b) why the nonlinear growth wrt data size?
I tested an XLL returning a 200x100 array and its virtually instantaneous. So the problem must be either dependency building or calculation or erasing/buildng the cell table.
Try
- switching calculation to manual to turn off calculation
- setting forcefullcalculation to true to switch off dependency building
- test with an empty workbook to see if it is caused by the workbook contents
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;