This is the way I did it. I wouldn't have got anywhere close to this tonight, if it wasn't for mrfluff at MrExcel.
For references see my question at Mr Excel I posted asking for help re:
looping over columns and rows of any particular sheet on an earlier version of the code I developed, which became "use the usedrange" courtesy of the excellent help I received from the wonderful @mrfluff over there.
Finds all refs and activates each as it goes and gives you the option on each found ref to stop the program and deal with it there and then in that cell. You can restart again after dealing.
Sub FindRefsandErrorsinWorkbookBySheets24()
Dim lastColumn As Integer
Dim myCell As Range
Dim LastRow As Long
Dim myArray() As Variant
Dim x As Long
'Determine the data you want stored
Set DataRange = ActiveSheet.UsedRange
'Resize Array prior to loading data
'nope - ReDim myArray(DataRange.Cells.Count)
refcount = 0
Dim ws As Worksheet
'Dim starting_ws As Worksheet
'Set starting_ws = ActiveSheet 'remember which worksheet is active in the beginning
For Each ws In ThisWorkbook.Worksheets
ws.Activate
For Each myCell In ws.UsedRange 'ws.UsedRange.SpecialCells(xlFormulas, xlErrors) 'ws.UsedRange
If myCell.Text = "#REF!" Then
refcount = refcount + 1
myCell.Select '' 1. COMMENT OUT FOR SPEED
myCell.Offset(0, 1) = "This was a ref in " & myCell.Address
ReDim Preserve myArray(x)
myArray(x) = myCell.Address
x = x + 1
MsgBox "Ref Found in " & myCell.Address ''2. COMMENT OUT FOR SPEED
If MsgBox("do you want to edit? - press cancel", vbOKCancel) = vbCancel Then Exit Sub ''3. COMMEMT OUT FOR SPEED
ElseIf IsError(myCell.Value) Then
myCell.Offset(0, 1) = "Do you know you had different tyoe of error in " & myCell.Address & "???"
End If
Next myCell
'MsgBox ws.Name
Next ws
MsgBox "Finished Checking. There where " & refcount & "ref errors! and they were in"
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
'Range("A1:A" & UBound(myArray)).Value = myArray(x)
For x = LBound(myArray) To UBound(myArray)
Debug.Print myArray(x)
'With sheet
'End With
Next x
With ActiveSheet
For x = 1 To UBound(myArray)
Cells(x, 1).Value = myArray(x)
Next x
End With
''Dim sheet As Worksheet
''Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
'Range("A1:A" & UBound(myArray)).Value = myArray(x)
End Sub
It also finds all and each refs and gives you a list at the end where they are.
I've assumed you want them one by one and you can stop the macro at a particular one to fix it. But if you don't, comment out the entire 3 lines relating to message boxes, where I've written COMMENT OUT THIS ENTIRE LINE IF YOU WANT SPEED . Each one is '1, '2 and '3.
I had them in at the beginning, but once I was assured they worked, I removed them for speed of my testing, before putting them back in just now.
So those 3 sections each having a comment in themselves '1... '2... '3... comment out entirely those 3 lines and you've got a much faster macro with only a final message box with total number of refs, and the output of all the refs in immediate window and a new created sheet at the end.
I prefer the macro without those 3 lines inside, as it runs much more smoothly and quickly. But you were speculating at first if it would be good to edit-investigate the refs as you go/as you find them. So that's why I put them back in just now. But you can remove those 3 lines for a much faster less interrupted sub (& you get the array - total and print out of all the refs locations at the end anyway, so if I were you I'd live without those 3 lines).
Hope I helped. It worked for me. :)
Here is the macro (my preferred one, even if it doesn't show you the refs as it runs or gives you options to stop.) without the message boxes or activates and without the pasting of offsets (which I only had in the 1st because I found them useful on development):
Sub FindRefsandErrorsinWorkbookBySheets245()
Dim lastColumn As Integer
Dim myCell As Range
Dim LastRow As Long
Dim myArray() As Variant
Dim x As Long
'Determine the data you want stored
Set DataRange = ActiveSheet.UsedRange
'Resize Array prior to loading data
'nope - ReDim myArray(DataRange.Cells.Count)
refcount = 0
Dim ws As Worksheet
For Each ws In ThisWorkbook.Worksheets
ws.Activate
For Each myCell In ws.UsedRange 'ws.UsedRange.SpecialCells(xlFormulas, xlErrors) 'ws.UsedRange
If myCell.Text = "#REF!" Then
refcount = refcount + 1
' myCell.Select '' 1. COMMENT OUT FOR SPEED
' myCell.Offset(0, 1) = "This was a ref in " & myCell.Address
ReDim Preserve myArray(x)
myArray(x) = myCell.Address(, , , 1) '' THIS GETS YOU THE SPECIFICS (SHEET NUMBER TOO)
x = x + 1
' MsgBox "Ref Found in " & myCell.Address ''2. COMMENT OUT FOR SPEED
' If MsgBox("do you want to edit? - press cancel", vbOKCancel) = vbCancel Then Exit Sub ''3. COMMEMT OUT FOR SPEED
' ElseIf IsError(myCell.Value) Then
' myCell.Offset(0, 1) = "Do you know you had different tyoe of error in " & myCell.Address & "???"
End If
Next myCell
Next ws
MsgBox "Finished Checking. There where " & refcount & "ref errors! and they were in"
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
For x = LBound(myArray) To UBound(myArray)
Debug.Print myArray(x)
Next x
With ActiveSheet
For x = 1 To UBound(myArray)
Cells(x, 1).Value = myArray(x)
Next x
End With
End Sub
They are identical. The only difference is ' lines which changes behaviour.
It just occurred to me (your language phrase: detect them and activate the cells, Where they appear (optionally one by one) Its got me thinking, how would could you have the option to activate cell without knowing where the option is visibaly other than a list given to you or message box (i.e how could you be given option to activate or not without seeing it?)
But strictly going by your words alone, I re-wrote the original macro (which has those unneccissary and potentialy data overwriting offsets) to do that exactly.
The ref is informed to you by a message box, and then a 2nd message box asks if you wish to deal with that Ref (with address) or continue. Yes would select the cell and end the macro/sub. No would just continue.
SO This one is not activating any cell or any worksheet until you decide. You get your messages one by one per ref, and any message box with a particular ref your interested in, is the one you decide to activate-select that ref cell and deal with or not. slightly different. The sheet and cell is only 'activate' (selected) and the program stopped, when you decide based on being told by msgbox (I guess you have a good mental map of where these cells are in your sheets, and you already know which one is more important!?).
With thanks to a go to guy (Jon) at excelcampus and the people at automateexcel here
This one works also. All 3 do, slightly differently, depending on how you read your words.
Sub FindRefsandErrorsinWorkbookBySheets26()
Dim lastColumn As Integer
Dim myCell As Range
Dim LastRow As Long
Dim myArray() As Variant
Dim x As Long
'excel campus - https://www.youtube.com/watch?v=rCh7ki9yVsM
Dim Answer As VbMsgBoxResult
'Determine the data you want stored
Set DataRange = ActiveSheet.UsedRange
'Resize Array prior to loading data
'nope - ReDim myArray(DataRange.Cells.Count)
refcount = 0
Dim ws As Worksheet
'Dim starting_ws As Worksheet
'Set starting_ws = ActiveSheet 'remember which worksheet is active in the beginning
For Each ws In ThisWorkbook.Worksheets
''' ws.Activate 'you could comment this out too if you dont need or want to see the sheets, and put it back in the "yes portion" of "i wasnt to deal with" - as you kinda implied you want to be chooser of what ref to activate
For Each myCell In ws.UsedRange 'ws.UsedRange.SpecialCells(xlFormulas, xlErrors) 'ws.UsedRange
If myCell.Text = "#REF!" Then
refcount = refcount + 1
'''''myCell.Select '' deleted because your wording kind of suggests you want to choose when to select/activate the cell.
myCell.Offset(0, 1) = "This was a ref in " & myCell.Address
ReDim Preserve myArray(x)
myArray(x) = myCell.Address
x = x + 1
MsgBox "Ref Found in " & myCell.Address ''2. COMMENT OUT FOR SPEED
''''If MsgBox("do you want to edit? - press cancel", vbOKCancel) = vbCancel Then Exit Sub ''3. COMMEMT OUT FOR SPEED
Answer = MsgBox("Do you want to go to cell" & myCell.Address & " and fix?", vbYesNo)
If Answer = vbYes Then
ws.activate
myCell.Select
Exit Sub
Else
'MsgBox "No"
End If 'must thank also - https://www.automateexcel.com/vba/yes-no-message-box/ - for this
ElseIf IsError(myCell.Value) Then
myCell.Offset(0, 1) = "Do you know you had different type of error in " & myCell.Address & "???"
End If
Next myCell
'MsgBox ws.Name
Next ws
If refcount = 0 Then
MsgBox "Finished Checking. There were " & refcount & " Ref Errors!"
Exit Sub
End If
MsgBox "Finished Checking. There where " & refcount & "ref errors! and they were in"
Dim sheet As Worksheet
Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
'Range("A1:A" & UBound(myArray)).Value = myArray(x)
For x = LBound(myArray) To UBound(myArray)
Debug.Print myArray(x)
'With sheet
'End With
Next x
With ActiveSheet
For x = 1 To UBound(myArray)
Cells(x, 1).Value = myArray(x)
Next x
End With
''Dim sheet As Worksheet
''Set sheet = ActiveWorkbook.Sheets.Add(After:=ActiveWorkbook.Worksheets(ActiveWorkbook.Worksheets.Count))
'Range("A1:A" & UBound(myArray)).Value = myArray(x)
End Sub
Quickest/simplest way imo to handle the last or only potential error in this code and terminate cleanly (that is, if myarray was empty or it found no refs) and account for empty myarray/null array, no ref error situation, was to If refcount = 0 Then otherwise determining if the array was isempty(myarray) = true proved to be a little too difficult extra work & complicated at his time.