VBA ClearContents initiates UserDefinedFunction update - vba

I am trying to clear the contentents of some cells and it is causeing the program to crash. While stepping through the code using the debugging tool the line
Range(light.Offset(0, 4), light.Offset(0, 9)).ClearContents
executes and then I step and instead of executing the next line of code, the debugger jumps to the function call:
Function overhaulCosts(buoyName As Range, district As String, orgComSplit As Range)
I know user defined functions are updated whenever cells that reference them are changed, but in this case none of the cells that are being cleared use the function or are referenced by a cell that uses that function. Does a ClearContents call in a workbook always trigger a user defined function call?

It seems it is triggering 'Application.Calculate'. I believe you can stop this by temporarily disabling automatic calculations.
Application.Calculation = xlCalculationManual
Range(light.Offset(0, 4), light.Offset(0, 9)).ClearContents
Application.Calculation =xlCalculationAutomatic

Related

VBA Function #VALUE and debugging disabled

Every time I try to put some arguments in a Function Excel would return #VALUE. Below is one of the examples. Also, I cannot debug when I put arguments in. What is the possible cause? Thank you.
Function lastrowC(SelectedCell As Range)
sc = SelcetedCell.Column
lastrowC = ActiveSheet.Cells(Rows.Count, sc).End(xlUp).Row
End Function
Your code does not work due to a typo. If you add Option Explicit to the top of your code, then try to calculate, VBA will
show you the problem (you misspelled Selected)
Either way, please consider the below code which will target the correct worksheet rather the active worksheet. Your code, as is, will likely look to the wrong sheet to determine the last row under certain circumstances. You need to look at the sheet where the range was selected, which is not always going to be the same as the active sheet
Paste the below code in a Module to call function from excel
Function lastrowC(Target As Range) As Long
With Target.Worksheet
lastrowC = .Cells(.Rows.Count, Target.Column).End(xlUp).Row
End With
End Function

Run-Time Error '1004' in VBA Subroutine

There seems to be something wrong with one of my Excel Objects. Take a look at the below snippet. I created the subroutine Run_all(), and when I step through, it'll go up to the Function row_count() and start executing, however, when it gets to the first highlighted row, I get the error.
**The Sheet that I'm referencing in the function is typed correctly. For example, if I run the bottom subroutine CA_Copy_Paste_, it works correctly and I get no errors.
Why is Excel not recognizing "Sheet 3" in the function? For more context, it only works if I type "Sheet4". Does not work on "Sheet1" or "Sheet2" either.
If you insist on using .Select and .Activate to accomplish your goals then you must activate the worksheet before activating or selecting a cell or range of cells on that worksheet.
worksheets("sheet 3").activate
activesheet.range("c4").activate
If you wish to use some 'shorthand' to try and accomplish this in a single line of code then switch to the Application.GoTo method.
Application.Goto reference:=worksheets("sheet 3").range("c4")
In any event, you are best off avoiding the use of select and activate. See
How to avoid using Select in Excel VBA.

Non-volatile UDF always recalculating

I am trying to make a non-volatile UDF but it seems not possible. So here is a my very simple test-UDF:
Option Explicit
Dim i As Integer
Sub Main()
i = 0
[A1] = "zyy"
MsgBox i
End Sub
Function Test(rng As Range)
Application.Volatile (False)
Test = rng.Value
i = i + 1
End Function
I got a otherwise empty worksheet that uses this function a couple of times, and every time I call Main() and change any cell on the sheet with the UDFs all of them recalculate. How can I make this (any) UDF no-volatile? The Application.Volatile (False) should have that effect but obviously doesn't work.
Edit: If I change a cell manually it works like intended, it only recalculates when I change a cell via VBA. Is this normal behaviour or can I change it?
I am posting a new answer instead of trying to salvage my previous answer, even though I think they point to the same thing, it will be better to start fresh.
Background:
Previously I had tested your code and the results were exactly as I would expect them to be if you simply omit the False from that statement. I have never seen any reason to explicitly do Application.Volatile (False), because that is equivalent to simply omitting the statement entirely.
If omitted, the function is non-volatile and the UDF evaluates only when a reference changes (i.e., not when other, non-referent cells change)
If included as Application.Volatile (or Application.Volatile
(True), the UDF becomes volatile and any change to the worksheet
will force re-evaluation.
Continuing investigation
You commented that you still observed otherwise. So I made some changes to my code and tested again. All of a sudden weird stuff was happening. No matter what I did with the Application.Volatile function, any change to the worksheet was re-evaluating the UDF.
This didn't make sense, so I started googling and doing a little more testing.
In my tests I created three functions.
The first one is explicitly Volatile:
The second one is explicitly not volatile.
The third omits any statement of volatility.
I put one instance of each formula on a worksheet. Each referenced a different range.
I tested each of these by making changes to the worksheet (manually), and through a named subroutine. I used a Print statement and monitored the Immediate window in the VBE to confirm that in all cases, the functions evaluated (or not) only as expected. The first one always evaluates, while 2 and 3 only evaluate if reference range changed.
Function f_appvol(rng As Range)
Application.Volatile
Debug.Print "f_appvol"
f_appvol = rng.Value
End Function
Function f_appNOTvol(rng As Range)
Application.Volatile (False)
Debug.Print "f_appNOTvol"
f_appNOTvol = rng.Value
End Function
Function f_omit(rng As Range)
Debug.Print "f_omit"
f_omit = rng.Value
End Function
Then it got weird...
I started making changes within these functions and they start to behave wonky.
Specifically I got lucky and noticed that if I changed my non-volatile function to a volatile one, then all functions started acting as if they were volatile -- even the f_omit. I believe this may be the condition you are experiencing.
Somehow, we have managed to "confuse" Excel
I saved the workbook and tried again... back to normal!
Then I changed the argument in the volatile statement, and the strange behavior happened again.
This appears to be a bug
I don't see anything in the documentation that suggests this is normal/expected behavior, and it sure as hell is not desirable behavior from a debugging standpoint. This is the sort of thing that makes you pull out your hair in frustration!
I am using Excel 2010, Win 7 64b.
Resolution
The cause of the error seems to be making change to the volatility of a UDF.
In order to restore expected behavior, it seems necessary to save the workbook. Again, I don't think this is normal but it seems to solve your problem (or at least a very similar problem that I was able to replicate while troubleshooting yours).
On a possibly related note
There appears to be at least one bug related to volatility, as mentioned here. I link to it mainly because this writer echos my own sentiment: there is no reason to do Application.Volatile (False) because that is (or should be) the "normal" state of a UDF.
I have to admit that I had never seen the point of using Application.Volatile False since thats supposed to be what you get if you omit the Application.Volatile statement altogether.
I found the solution, and it is indeed a very simple one but also made this hard to debug:
If you make any change to your VBA code all the UDF get flagged for recalculation!
I modified the degug code of David:
Sub main()
'nothing depends on the Value in [A13]
[A13] = ""
[A13] = "hgdg"
[A13] = ""
i = 46
End Sub
Function f_appvol(rng As Range)
Application.Volatile
Debug.Print "f_appvol"
f_appvol = rng.Value
End Function
Function f_appNOTvol(rng As Range)
Application.Volatile (False)
Debug.Print "f_appNOTvol"
f_appNOTvol = rng.Value
End Function
Function f_omit(rng As Range)
Debug.Print "f_omit"
f_omit = rng.Value
End Function
After entering the code and running it for the first time, only f_appvol is recalculated. If you now change i=46 to i=47 and execute it, all the UDF get recalculated. All subsequent runs after that first run after the change give the expected behaviour.

'28' Out of Stack Space. Worksheet_Change and Application.ScreenUpdating

thanks in advance for any clarity you can offer.
In an Excel Workbook with many modules and worksheets, at the bottom of the VBA code for SHEET2, there is this Subroutine:
Private Sub Worksheet_Change(ByVal Target As Range)
Dim TargetCells As Range
Set TargetCells = Range("B1000:B1029")
If Not Application.Intersect(TargetCells, Range(Target.Address)) Is Nothing Then
Call SpecificSubRoutine
End If
End Sub
My understanding of this code is that it watches the entire sheet for ANY changes. If ANYTHING is changed, anywhere on the sheet, it runs the If statement. The If statement fails in the event that any of the changes made to the sheet take place outside of the specified TargetCells range, but this Sub still tries to validate the If statement EVERY time ANYTHING is changed on the sheet.
Now, you might be able to guess that my problem is some stack overflow. (Run-time error '28': Out of Stack Space)
Whenever the Worksheet_Change Sub runs, if the changes to the sheet were made inside of the TargetCells range, it calls SpecificSubRoutine which populates cells, which triggers the Worksheet_Change Sub for every time SpecificSubRoutine populates ANY cell. (SpecificSubRoutine also calls different modules, which of course populate cells, which of course trigger the Worksheet_Change Sub)
Not so good.
Also, most of the subroutines throughout the application are wrapped in Application.ScreenUpdating = False / Application.ScreenUpdating = True, which I mistakenly thought would limit the number of times Worksheet_Change is called to once, immediately after Application.ScreenUpdating = True runs.
NOTE OF IMPORTANCE: Neither SpecificSubRoutine nor any of the Subroutines called by it populate cells in the TargetCells range. I'm not quite that dim...
Here are my questions:
Is there a way to narrow the scope of what triggers the Worksheet_Change Sub, so that only changes in the TargetCells range triggers it? (instead of changes anywhere in the sheet)
Is there a way to do what I mistakenly thought that Application.ScreenUpdating would do? (make changes to the sheet all in one bulk update, as opposed to triggering a change with nearly every step)
Also, as an extra curiosity, is there a way to have Worksheet_Change watch 2 specific ranges (instead of the whole sheet?) Knowing how to do this would be paramount, and would likely solve all of the problems on this sheet.
My intuition is to add an End to the last part of SpecificSubRoutine, or to the end of any/all of the Subroutines called by it, but I'm just not sure this will circumvent the looping through Worksheet_Change multiple times, since Application.ScreenUpdating doesn't bulk update like I thought.
Ideas?
Part 1: No - the event handler responds to all changes on the sheet: any filtering in how you respond to that change must occur in the handler itself.
Part 2: answered by #simoco
Part 3 (and incorporating simoco's suggestion):
Private Sub Worksheet_Change(ByVal Target As Range)
Application.EnableEvents=False
If Not Application.Intersect(Me.Range("B1000:B1029"), Target) Is Nothing Then
Call SpecificSubRoutine
End If
If Not Application.Intersect(Me.Range("D1000:D1029"), Target) Is Nothing Then
Call SomeOtherSpecificSubRoutine
End If
Application.EnableEvents=True
End Sub

Recursive call on the worksheet change in VBA

I have created the workbook with multiple sheet, i am trying to use WorkSheet_Change on Sheet1, i.e. something change on sheet1 is getting copied to sheet2. Similarly if anything change to Sheet2 i want to make similiar change on Sheet1 as well.
On doing so there is recursive call on both sheet please let me know how i can avoid this.
you should disable events when calling your macro:
Sub Donot_Fire_Events()
Application.EnableEvents = False
' Coding to skip these events
Application.EnableEvents = True
End Sub
Put a new global variable in a Module and call it bAutoUpdating As Boolean for example.
When the _Change code runs it should set this to true. Also any change routine should not fire if this is true. At the end of each _Change routine set back to bAutoUpdating = false