Custon fucntion applies to entire workbook instead single sheet - excel

I use popular custom function which I found on the internet on one of vba blogs. It reads text cell as if it be formula (i.e. "=A2+B2" or "=ABS(A2+B2)", I created them by using CONCATENATE function, in workbook they are without quotation marks). The code goes:
Function Eval(Ref As String)
Application.Volatile
Eval = Evaluate(Ref)
End Function
In my workbook I have multiple sheets which are exact same copies except 2 columns of data, which calculate some descriptive statistics (i.e. sum, average, standard deviation etc.), the formulas are in my source sheet, copied sheet have formula like: Eval(sourceSheet!A1) and A1 contains text of formula like above. The problem is that to apply macro after loading it, I need to pres F9 to refresh (sometimes several times). It makes refreshing ALL my copied worksheets with the data I have in worksheet I am refreshing. So for example: if i refresh in worksheet 3 and sum of data was 5 it changes sum to 5 in all other sheets. I guess somehow my code makes the function applied to entire workbook instead of single worksheets like every other excel function.
So I have 2 questions:
Is there any way to change the code so my custom function will only apply to worksheet I put it in?
Can you post me a macro code for refreshing entire workbook with every single click of left mouse button?
Thank you in advance

Thats a rather buggy UDF: Evaluate always takes unqualified references as referring to the active sheet.
You really need to use Worksheet.Evaluate. Try something like this that assumes that any unqualified references in Ref are to the sheet that Ref is on
Function Eval(Ref As range)
Application.Volatile
Eval = ref.parent.Evaluate(Ref.value)
End Function
Or if you want it to refer to the sheet that the UDF is being called from try this
Function Eval(Ref As variant)
Application.Volatile
Eval = Application.Caller.Parent.Evaluate(Ref)
End Function
There are also a number of strange things/Quirks/bugs with evaluate you should be aware of: see my blog post
https://fastexcel.wordpress.com/2011/11/02/evaluate-functions-and-formulas-fun-how-to-make-excels-evaluate-method-twice-as-fast/

Related

My Excel workbook with custom formulas breaks when I use other workbooks simultaneously

I´m using an Excel workbook with a custom formula for taking a value from the previous worksheet. I use this formula like INDIRECT(SHEETNAME(SHEET(A1)-1)&"!A1"), so SHEET(A1) returns the current sheet number, and SHEETNAME(SHEET(A1)-1) returns the name of the previous sheet, then I use INDIRECT to take the value A1 from that previous sheet.
Here is the code for the custom sheetname formula:
Function SHEETNAME(number As Long) As String
SHEETNAME = Sheets(number).Name
End Function
The problem is that when I use other workbook at the same time, the mentioned command returns #VALUE!.
Thanks for the help! :)
You should always fully qualify.
So instead of Sheets(number).Name, try ThisWorkbook.Sheets(number).Name
Not doing so can lead to bugs that are difficult to diagnose.
I would always suggest avoiding "ActiveWorkbook" unless you specifically need it.

Moving or saving as .xlsm file breaks macros

I have a .xlsm file which use a variable that gives the name of other spreadsheet using their index (it uses GET.WORKBOOK(1)). In order for this to work, I have to save the file as a .xslm file.
This file is saved on a onedrive and working but when saving a copy elsewhere, the macros are completely broken and I get #NAMES errors in my cells using it.
I tested it with a smaller file and I get exactly the same behavior.
This is the macro saved in the name manager.
=REPLACE(GET.WORKBOOK(1),1,FIND("]",GET.WORKBOOK(1)),"")
I tested it in a small example: one excel .xslm file with one sheet, in one cell calling the variable should give me 'Sheet1'. Once I move this file and try to call this macro again I get #NAMES
You can write a short user defined function (in a module)
Option Explicit
Public Function GetWorkbookNameByIndex(Index As Long) As Variant
Application.Volatile
If Index <= ThisWorkbook.Sheets.Count Then
GetWorkbookNameByIndex = ThisWorkbook.Sheets(Index).Name
Else
GetWorkbookNameByIndex = CVErr(xlErrNA)
End If
End Function
So you can use it as a formula eg:
=GetWorkbookNameByIndex(A1)
And it will return the following:
Image 1: Result of the function: If index is out of range it returns #N/A (=#NV in the image above because of German screensot).
Note that the function has to be volatile, otherwise the formula won't update if a sheet name gets changed. Volatile functions are re-calculate on every calculation in the sheet and therefore come with a more heavy load on calculation. Volatile functions should not be used extensively or calculation will slow down significantly.
The fact that it is volatile will trigger an update if a sheet name gets changed or a sheed gets deleted or moved but actually not if a new sheet is added. Therefore you would need to either manuall re-calculate by pressing F9 or use the NewSheet event:
Private Sub Workbook_NewSheet(ByVal Sh As Object)
Application.Calculate
End Sub
Same for the NewChart event if this is relevant for you.

Can I prevent cells being dirtied when a Workbook opens [Mac]?

I have a UDF that I'm using throughout a Workbook, when I save and reopen the Workbook and then try to recalculate a single cell, Excel will update that cell but it will also recalculate every other cell containing that formula in the Workbook.
Here's a simple formula that demonstrates this issue:
Public Function MyFormula(a As Integer, b As Integer) As Integer
Debug.Print "calculating: " & Application.Caller.Address
MyFormula = a * b
End Function
I would expect that after recalculating a single cell to see a single log statement, but I'm actually seeing 4 (I have 4 cells with this UDF in the Workbook).
I'm guessing that when I save & reopen the Workbook, Excel is marking the cells as "Dirty" and in need of recalculation, but that doesn't make sense. According to the docs (https://learn.microsoft.com/en-us/office/client-developer/excel/excel-recalculation#dependence-dirty-cells-and-recalculated-cells) dirty cells are defined as those who's dependancies have changed:
When new data or new formulas are entered, Excel marks all the cells that depend on that new data as needing recalculation. Cells that are marked in this way are known as dirty.
My UDF isn't volatile and I haven't altered any dependancies, so why is Excel recalculating the all cells and how can I stop it from doing so?
(By the way, I'm aware that Manual calculation mode exists. I'd like to be able to use Automatic mode and allow automatic cell updates, but just only when dependancies have changed)
I've since found that this issue is only present on Excel for Mac (tested on the 2016 version).

What is the best way to cut and paste a column with a defined name to a new worksheet, and why doesn't my code work?

I am attempting to efficiently copy columns of data from one worksheet to a second worksheet in Excel using VBA, starting with a defined name for the column.
I am unsure why my code doesn't work. I cannot emphasis enough, how little I know about coding. I am attempting to teach myself VBA in order to manipulate vast quantities of data in Excel.
Function SortDataC()
'cuts and pastes columns from the unsorted worksheet to the sorted worksheet
Worksheets("UnsortedData").Range("DeltaModScore").Copy Destination:=Worksheets("SortedData").Columns(1)
End Function
DeltaModScore is the column header. If I look in defined named it is present on the sheet UnsortedData with workbook scope. Thus, I assume I have screwed up the syntax somewhere?
I have used the term Sheets("UnsortedData").Range..... as well as Worksheets.... as you see above. I've been basically searching the web for code examples and trying to get them to work with my data. Inevitably, I end up with errors I have much difficulty fixing. I hope this is something simple someone can point out.
You only require the single top left cell of a destination to complete a Copy & Paste.
SUB SortDataC()
'COPIES and pastes columns from the unsorted worksheet to the sorted worksheet
Worksheets("UnsortedData").Range("DeltaModScore").Copy _
Destination:=Worksheets("SortedData").Cells(1, "A")
End SUB
Functions are intended to return a value. If you simply want to complete an operation, a sub procedure is more appropriate.

Having Excel Fields Auto Update when New Data Added

I have an Excel doc that starts with some fields that come from calculations done on the rows below it. To do the calculations I currently have a module with about 4 functions that loop through rows 20 through N(first blank cell). These functions are called straight from the cells at the top of the sheet. The problem is that the calculations at the top are not updating whenever someone adds/removes data from the rows below. How can this be accomplished?
If your functions are Excel VBA user-defined functions called from worksheet cells, then you will get this not-recalculating behaviour if the UDF refers to cells that are not in the input parameters of the UDF.
If this is the case a good solution would be to define some Dynamic Named Ranges that expand/contract as data is added/deleted and use them as input to the function.
Another solution would be to add Application.Volatile to your UDF, but this has the undesirable side-effect that your UDFs will be recalculated at every calculation which can be painfully slow.
If I understand your question correctly, you can use Worksheet_Change event to accomplish such tasks.
In your sheet module, add a Worksheet_Change event:
Private Sub Worksheet_Change(ByVal rngChanged As Range)
' Call your subs and functions here
MsgBox "You just changed something!"
End Sub
Note that the Worksheet_Change sub must have one and only one argument of type Range. Excel will make it a reference to the range that was changed by the sheet user. If you want to observe its behaviour, try placing this line in the sub:
rngChanged.Interior.ColorIndex = 4
Read more e.g. here.

Resources