Triggering Worksheet Change in Excel VBA - vba

This is more of a general question but I was wondering what exactly triggers a Workbook_SheetChange() on Excel VBA. It claims to change when a value in a cell is changed, but when you try and drag instead of entering a value into a new cell, the macro doesn't trigger. Is there any way to go around that or is there another way to trigger a macro that will detect any change in a workbook?

For me it does seem to trigger the change event when dragging and dropping cells.
I'm using (In the "ThisWorkbook" Module);
Private Sub Workbook_SheetChange(ByVal Sh As Object, ByVal Target As Range)
Debug.Print Now
End Sub
Are you definitely using the WORKBOOK event and not the WORKSHEET event?
Edit: Phrasing

Related

How to trigger VBA Workbook_SheetCalculate Event?

I tried Workbook_SheetCalculate Event and tried to trigger it, but it did not work, although I recalculated the worksheet!
How to trigger this Event?
here is an example, in the worksheet for the event have the following code:
Private Sub Worksheet_Calculate()
MsgBox "Calculating"
End Sub
Then in the sheet, in any cell, enter =RAND()
The formula causes a recalculation and triggers the event.
Or from a standard module use the following:
Public Sub Test()
'Application.Calculate ''could use this event for the workbook
With Worksheets("Sheet5") 'sheet containing the event code
.Calculate
End With
End Sub
The key seems to be that there is something in the sheet to calculate e.g. =RAND().
I remembered from another post, at some point, a link to the following Excel’s Smart Recalculation Engine
A quick extract says:
Excel normally only calculates the minimum number of cells possible.
Excel’s smart recalculation engine normally minimises calculation
time by tracking changes and only recalculating
Cells, formulae, values or names that have changed or are flagged as needing recalculation.
Cells dependent on other cells, formulae, names or values that need recalculation.
So, if you just had constants in the sheet, even if you issue a Worksheet.Calculate the msgbox wouldn't appear. You could test this by removing the =RAND() from the sheet and just putting 1 in the cell.
If I have two sheets each with a single non-volatile formula, and this in the workbook module:
Private Sub Workbook_SheetCalculate(ByVal Sh As Object)
Debug.Print Sh.Name
End Sub
I see both sheets names on calling:
Application.CalculateFull
or:
Application.CalculateFullRebuild
but no output with:
Application.Calculate
If I add a volatile formula to one of the sheets then I get that sheet when calling Application.Calculate.
If you're still having problems then you'd need to post a few more details including your event code and what types of formulas you have on your sheets.

Combobox linked cell value change does not fire worksheet change event

As per the question: selecting a new value in an ActiveX combobox linked to a cell by it's .LinkedCell property does not fire the worksheet change event.
I know there are various events for combo boxes like it's own change event but none of them are really suitable for what I need to do (custom data validation on the changed cell).
As a workaround I pass the .LinkedCell to my validation code on the combobox mouse up and key up events (I can't use lost focus... long story, and on change fires on every character change which is too much).
Does anyone know of a cleaner way to pass the value around at the event level once the user has finished using the control?
If you want to trigger the ChangeEvent in a worksheet, without doing anything, here is a way to do it:
In a module:
Option Explicit
Public Sub CheckMe()
Application.Run "tblDB.Worksheet_Change", tblDB.Cells(1, 1)
End Sub
In a workbook, named tblDB:
Option Explicit
Private Sub Worksheet_Change(ByVal Target As Range)
Debug.Print "triggered"
End Sub
Now, whenever you run the CheckMe, the Worksheet_Change event would be triggered.

Excel VBA DoubleClick

I'm working on a work project where I have an excel sheet with values that turn red when they are out of spec. What I'd like to do is be able to double click on a cell and have the sheet in my workbook pop up that has trending data on it. I have already created the sheet with the graph on it. Long story short, I'd like to be able to double click on a specific cell and have it bring up the corresponding sheet.
I have tried this code, and it will not work. Is anyone able to maybe write code from scratch or alter the code so I could use it? The cell I'm trying to click on is N9, and the sheet I want it to open is called "Alpha Final Rinse"
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, cancel As Boolean)
Sheets("Alpha Final Rinse").Select
End Sub
I'm doing this in Excel 2013. Thank you!
If you only want N9 to be able to switch focus to another worksheet, isolate Target with the Intersect method.
In the data worksheet's code sheet:
Private Sub Worksheet_BeforeDoubleClick(ByVal Target As Range, cancel As Boolean)
If Not Intersect(Target, Range("N9")) Is Nothing Then
cancel = True
Worksheets("Alpha Final Rinse").Activate
End If
End Sub
Note that cancel = True is necessary to stop the user entering in-cell edit mode (assuming that has been enabled in Options).
Your code will work if:
it is installed in the worksheet code area of your data sheet (the sheet whose cells you are double-clicking)
macros are enabled
the file type is .xlsm rather than .xlsx

Referencing the selection in deactivated Workbook

Private Sub Workbook_Deactivate()
ThisWorkbook.ActiveSheet.Selection.Copy
End Sub
I'd like to copy the selection in the deactivated workbook. But this doesn't work, indeed, I got a run-time error.
Damn! It is possible!
Private Sub Workbook_Deactivate()
ThisWorkbook.Windows(1).Selection.Copy
End Sub
Explanation:
Both ActiveSheet and Selection are children objects of the Application object, not the Workshet or Workbook objects. (See MSDN: Selection and ActiveSheet.) Selection means the currently selected item in the active window. Same for ActiveSheet.
Now it turns out that you can specify a window object for both of them. Normally every Workbook has one window, but you can create multiple windows for each open workbook. Anyhow, every open workbook that you can click and select will have at least one window. This is whateverworkbook.Windows(1).
ThisWorkbook always references the workbook running the macro (that means the workbook actually containing the VBA code). In your case, that is the one you are leaving. (Unless you want the macro to run from any workbook you are deactivating, in which case you'd have to come up with a custom event handler that catches each workbook deactivate event...)
And that's it, really. You can reference a selection in another workbook, you just have to attack it through it's Window.
Thanks for the good question, I have learned something very valuable today. :)

Append Procedure to Event upon User Action

Say, I have a procedure which changes the random colour of a cell based on selection change. I know that I can code in a procedure for the worksheet SelectionChange event.
I guess Im asking, as in javascript where we can use addEventListeners, can we do something similar in Excel VBA.
What I am wondering is can this be done dynamically? I.e. when a user chooses an option, then I bind a procedure to the event SelectionChange of the worksheet.
Note, I know that I could declare a global boolean & use that to ascertain user action & use it in my SelectionChange event procedure.
Im just curious whether in Excel VBA, we can dynamically append procedures to events?
You can't dynamically assign event handlers. Excel will always call the built-in event handlers (SelectionChange, Calculate, etc) and there's no way to substitute your own. You can create your own Worksheet variable using the WithEvents keyword, however, and choose when to start receiving the events. For example, start with this structure in one of your worksheets:
Dim WithEvents MySheet As Worksheet
Private Sub MySheet_SelectionChange(ByVal Target As Range)
Debug.Print "Receiving events"
End Sub
As long as MySheet isn't bound to an active sheet, you're not going to receive any events. When you're ready to begin, call a custom subroutine to do the assignment:
Public Sub DoIt()
Set MySheet = Sheet1
End Sub