I'm doing a few things at once which I believe may be causing issues. I've tested this VBA in Office 2013 and Office 2016 under Windows 10.
I have a multitude of worksheets, each of which is titled based on the month and year (ex: "November 2018", "December 2018", etc.). I'm using VBA to do two (separate) things:
- Get the Active Worksheet's name
- Traverse a previous worksheet's data
VBA Code:
Public Function RelSheet(iPos As Integer, zRange As String)
'Relative Worksheet Reference Facility
'eg: =RelSheet(-1,"A3") = Cell A3 in Previous (Left) WSheet
'eg: =RelSheet(1,"A3") = Cell A3 in Next (Right) WSheet
'eg: "#Error" when reference does not exist
'eg: Can do maths =RelSheet(1,"A3")*2
Dim shtActive As Worksheet
Application.Volatile True
Set shtActive = Application.Caller.Worksheet
On Error GoTo BadSheetReference
RelSheet = Sheets(shtActive.Index + iPos).Range(zRange).Value
GoTo ExitFunction
BadSheetReference:
RelSheet = "#Error"
ExitFunction:
End Function
Function TabName()
TabName = ActiveSheet.Name
End Function
In my worksheets, I'm tallying a summation month over month until a near year is created, then the tally begins again at 0 (or whatever value Jannuary contains). Cell C8 is the current month's value, cell C9 is the summation of the previous month's value (C9 of the previous worksheet) + the current worksheet cell's value in C8. The formula for that cell (C9) is as follows:
==IF(ISNUMBER(SEARCH("January", TabName())), C8, RelSheet(-1, "C9")+C8)
Unfortunately, once a worksheet name does contain the text of "January", all previous worksheets are also reverted to a sum of 0. I believe it is related to the RelSheet function and essentially recursively checking itself, but when I step through the code logically on paper, I don't see how it's doing this. My current workaround is just to manually set the value of the particular cell in a January worksheet to 0, and continue the formula on successive spreadsheets.
Sheets()
will refer to the active workbook - do you have multiple workbooks open? AlsoTabName = ActiveSheet.Name
would probably be a problem on inactive sheets – Tim WilliamsSheets
is an enumerable, and there's no guarantee that the the index is ordered in any way what-so-ever. You'd be much better off iterating theWorksheets
collection and checking the names. What happens if the use re-orders the sheets? – CominternSheets(2)
didn't reference the second tab in the workbook (assuming there are at least two tabs and no hidden ones) – Tim WilliamsActiveSheet
, it's whatever worksheet invoked the UDF: whether that sheet is "active" or not makes no difference. I'd suggest renamingshtActive
to e.g.callerSheet
, and the unqualifiedSheets
collection is, as Tim correctly warns above, implicitly referring to whatever theActiveWorkbook
is, which means the UDF will evaluate differently depending on whether the expected book is currently active or not. UseThisWorkbook.Worksheets
instead, to guarantee deterministic results. – Mathieu GuindonSheets
collection contains non-worksheet sheets; use theWorksheets
collection when you know you're getting aWorksheet
object (as opposed to, say, aChart
sheet). The important part is theThisWorkbook
qualifier, without which what sheet you get depends on what workbook is currently active, or (in other contexts) even where in the VBA project the code is written: identical code written in a standard module may not behave the same way when written in a worksheet module, unless it's properly/explicitly qualified with aWorkbook
object reference. – Mathieu Guindon