MajP
You've got your good things, and you've got mine.
- Local time
- Today, 12:38
- Joined
- May 21, 2018
- Messages
- 8,904
There is often a lot of confusion about Access Events and often answering questions posed here is difficult because of inaccurate terminology. People often say "Event" when it is unclear if they mean the actual event that takes place, the event procedure, or the event property. This thread will try to clarify the correct terminology and discuss the basic and advanced Event concepts. Please feel free to critique or recommend additional topics. I would like to clean this up eventually and make a sticky. I have included a db that demonstrates these concepts. This thread includes
- What is an Event and raising / handling events
- What are Event Properties
- What are Event Procedures / Event Handlers
- How a single function can handle multiple Events
- Handling events in external Classes (handling another form’s events)
- Handling other object’s events in custom classes
- Raising and handling Custom Events
A. Events raising and handling:
The best way to think of an event is an announcement (Raised) that something has happened and your code can then listen to this announcement and react to it (Handle). Events are Raised (announced) and code can Handle the announcement. Often people will say "I call this event" which is not correct when they mean they handle an event.
B. Event Properties:
In form or report design you see what are called Event Properties (examples afterupdate, onclick, onEnter). As you can see all event properties start with a preposition (On, before, after,...) which tell when the event takes place. These event properties do two things if filled in. One they tell the event to announce that it has occured. If left blank the event does not announce that it has occured. Two it describes what is listening for the event in order to handle it. There are three things that can handle an event: an event procedure, a macro, or a function. So the following can be put in an event property:
[Event Procedure] 'Informs that the event will be handled by an event procedure
[Embedded Macro] 'Informs that a macro will handle the event
=SomeFunctionName() 'Informs that a function will handle the event
C. Event Procedures / Event Handlers:
Event procedures are the VBA code that listens for an event to occur (Raise) and then reacts (Handles) to it. A more descriptive name is "event handler", because the event procedure code is not an "event" but a procedure that handles the event.
In something like vb.net the code construct makes this clearer. An event procedure will be followed by the names of the event/s it handles. So it would look something like this (pseudo code)
What is nice in .net and which you cannot do in vba is tell a procedure to handle multiple events. It would look something like this (pseudo code)
D. One Function to Handle Multiple Events:
As mentioned there is not a way to write a single event procedure to handle multiple events in vba, but you can do this using a function. You can make a function (it has to be a function not a sub even though it returns nothing). Then in each controls event properties, you do not put in "[Event Procedure]" you put in the name of the function like =SomeFunctionName(). This function now can handle multiple events.
E. Handling other Object Events in a different Class / With Events
This is probably one of the most underused and valuabe techniques. You can handle in one class the events of another object. For example form 1 opens form 2 as a pop up. Suppose when you do something like change a value in form 2 you want to do something in form 1. Often people will hard code form 2 to update form 1. This is bad design because you are tightly coupling form 1 and form 2. If you now want form 3 to call form 2 and do the same thing then the code in form 2 gets complicated. Instead you can have form 1 and form 3 handle events that occur in form 2 (an external object). Assume form 1 opens form 2 and form 2 has a combobox. You want to handle in form 1 the afterupdate of the combobox that takes place in form 2. To do this:
1. In form 1 define a variable using WithEvents
2. Set the variable to the external combobox in form 2
3. Make sure the combobox in form 2 raises the event by setting the eventProperty to "[Event Procedure]" You can do it manually in form2, but I usually do this by code so I do not forget. Remember if you leave the Event property blank it will not announce the event. In form 2 the combobox afterupdate needs "[Event Procedure]" either by doing it manually or by code.
4. Handle the after update event for your variable. Notice you are not handling CmboProducts event, you are handling your variable "Cmbo" that is set to cmboProducts. What is nice, is after you define your Cmbo using withevents it will appear in intellisense and you can choose it like other form 1 objects.
F. Handling other Object events in Custom Class
This is no different than what was described in E because a form or report's class is a class just like any custom class. So the technique is the same. To me this is the most powerful use of vba in Access. You can now build custom classes that extends the capability of a control or group of controls. You can handle multiple events from multiple controls and make them act basically as a user defined control. Here is the technique. This class only demonstrates the handling of events, this class has no real utility.
Class Code
In the form you would initialize the custom class like this
Even though the form does not have any beforeupdate or enter event handler the class will handle the events. Note there is an afterupdate event handler in the form's class and also the custom class. This actually demonstrates two different event handlers listening to the same event. This is important to prove the point that you do not call event handlers, they listen for the event.
G. Raising custom Events
In a class module you can raise your own custom events and then handle them. Since a form's or report's module is a class module you can do this here as well as in a custom class.
Public Event EventName(ReturnValue as datatype, ReturnValue2 as
datatype....)
So not only can you raise an event you can pass a value back. You have seen this before in the beforeupdate event of a form
Here is the Code in Form 2 to raise an event. If the final product selected has the letter "A" in the name it raises the event HasA and passes to the event handler the product name.
The code in Form 1 to trap this custom event is
Any questions or suggestions please provide.
- What is an Event and raising / handling events
- What are Event Properties
- What are Event Procedures / Event Handlers
- How a single function can handle multiple Events
- Handling events in external Classes (handling another form’s events)
- Handling other object’s events in custom classes
- Raising and handling Custom Events
A. Events raising and handling:
The best way to think of an event is an announcement (Raised) that something has happened and your code can then listen to this announcement and react to it (Handle). Events are Raised (announced) and code can Handle the announcement. Often people will say "I call this event" which is not correct when they mean they handle an event.
B. Event Properties:
In form or report design you see what are called Event Properties (examples afterupdate, onclick, onEnter). As you can see all event properties start with a preposition (On, before, after,...) which tell when the event takes place. These event properties do two things if filled in. One they tell the event to announce that it has occured. If left blank the event does not announce that it has occured. Two it describes what is listening for the event in order to handle it. There are three things that can handle an event: an event procedure, a macro, or a function. So the following can be put in an event property:
[Event Procedure] 'Informs that the event will be handled by an event procedure
[Embedded Macro] 'Informs that a macro will handle the event
=SomeFunctionName() 'Informs that a function will handle the event
C. Event Procedures / Event Handlers:
Event procedures are the VBA code that listens for an event to occur (Raise) and then reacts (Handles) to it. A more descriptive name is "event handler", because the event procedure code is not an "event" but a procedure that handles the event.
Code:
Private Sub cmbo1_Click()
'This is an event procedure that handles the combobox click event
End Sub
In something like vb.net the code construct makes this clearer. An event procedure will be followed by the names of the event/s it handles. So it would look something like this (pseudo code)
Code:
Private Sub cmbo1_Click() handles cmbo1.onclick
'This is an event procedure that handles the combobox click event
End Sub
What is nice in .net and which you cannot do in vba is tell a procedure to handle multiple events. It would look something like this (pseudo code)
Code:
Private Sub SomeProcedure() handles cmbo1.onclick, text1.afterupdate,
text2.afterupdate
'This is an event procedure handles the combobox click event and textbox 1,2 after update
End Sub
D. One Function to Handle Multiple Events:
As mentioned there is not a way to write a single event procedure to handle multiple events in vba, but you can do this using a function. You can make a function (it has to be a function not a sub even though it returns nothing). Then in each controls event properties, you do not put in "[Event Procedure]" you put in the name of the function like =SomeFunctionName(). This function now can handle multiple events.
Code:
Private Function SomeFunctionName()
'Often you want to do something based on which control's event is handled
dim ctrl as access.control
set ctrl = me.activecontrol
msgbox ctrl.name
end function
E. Handling other Object Events in a different Class / With Events
This is probably one of the most underused and valuabe techniques. You can handle in one class the events of another object. For example form 1 opens form 2 as a pop up. Suppose when you do something like change a value in form 2 you want to do something in form 1. Often people will hard code form 2 to update form 1. This is bad design because you are tightly coupling form 1 and form 2. If you now want form 3 to call form 2 and do the same thing then the code in form 2 gets complicated. Instead you can have form 1 and form 3 handle events that occur in form 2 (an external object). Assume form 1 opens form 2 and form 2 has a combobox. You want to handle in form 1 the afterupdate of the combobox that takes place in form 2. To do this:
1. In form 1 define a variable using WithEvents
2. Set the variable to the external combobox in form 2
3. Make sure the combobox in form 2 raises the event by setting the eventProperty to "[Event Procedure]" You can do it manually in form2, but I usually do this by code so I do not forget. Remember if you leave the Event property blank it will not announce the event. In form 2 the combobox afterupdate needs "[Event Procedure]" either by doing it manually or by code.
4. Handle the after update event for your variable. Notice you are not handling CmboProducts event, you are handling your variable "Cmbo" that is set to cmboProducts. What is nice, is after you define your Cmbo using withevents it will appear in intellisense and you can choose it like other form 1 objects.
Code:
Private WithEvents Cmbo As ComboBox
Private Sub cmdOpen_Click()
Set Cmbo = Nothing
DoCmd.OpenForm "form2"
'Set your variable to the combobox in form 2
Set Cmbo = Forms!form2.cmboProducts
'To ensure that the cmbo raises the afterupdate event need to add "[Event
Procedure]" in the event property in form 2
Cmbo.AfterUpdate = "[Event Procedure]"
End Sub
Private Sub cmbo_AfterUpdate()
'Now can trap an event from a control on another form
Me.txtOutPut = Nz(Cmbo, "Nothing Selected")
End Sub
F. Handling other Object events in Custom Class
This is no different than what was described in E because a form or report's class is a class just like any custom class. So the technique is the same. To me this is the most powerful use of vba in Access. You can now build custom classes that extends the capability of a control or group of controls. You can handle multiple events from multiple controls and make them act basically as a user defined control. Here is the technique. This class only demonstrates the handling of events, this class has no real utility.
Class Code
Code:
Private WithEvents mCmbo As ComboBox
Public Property Get Combo() As ComboBox
Set Combo = mCmbo
End Property
Public Property Set Combo(ByVal TheCombo As ComboBox)
Set mCmbo = TheCombo
End Property
Public Sub Initialize(TheCombo As ComboBox)
Set Me.Combo = TheCombo
'Need to ensure you raise the events you want to capture
Me.Combo.OnEnter = "[Event Procedure]"
Me.Combo.BeforeUpdate = "[Event Procedure]"
Me.Combo.AfterUpdate = "[Event Procedure]"
End Sub
'------------------------------------------------------ Trap Events --------------------------------------
Private Sub mCmbo_BeforeUpdate(Cancel As Integer)
MsgBox "Before update Trapped in custom class " & Me.Combo.Value
End Sub
Private Sub mCmbo_Enter()
MsgBox "Enter event Trapped in custom class " & Me.Combo.Value
End Sub
Private Sub mCmbo_AfterUpdate()
MsgBox "After update Trapped in custom class. This demonstrates two different event handlers trapping the same event. " & Me.Combo.Value
End Sub
In the form you would initialize the custom class like this
Code:
Public CC As CustomClassHandler
Private Sub Form_Load()
Set CC = New CustomClassHandler
CC.Initialize Me.cmboProducts
End Sub
Private Sub cmboProducts_AfterUpdate()
MsgBox "After update event handled in the form class " & Me.cmboProducts
End Sub
Even though the form does not have any beforeupdate or enter event handler the class will handle the events. Note there is an afterupdate event handler in the form's class and also the custom class. This actually demonstrates two different event handlers listening to the same event. This is important to prove the point that you do not call event handlers, they listen for the event.
G. Raising custom Events
In a class module you can raise your own custom events and then handle them. Since a form's or report's module is a class module you can do this here as well as in a custom class.
Public Event EventName(ReturnValue as datatype, ReturnValue2 as
datatype....)
So not only can you raise an event you can pass a value back. You have seen this before in the beforeupdate event of a form
Code:
Private Sub SomeControl_BeforeUpdate(Cancel as as integer)
‘cancel is passed when the event is raised by reference.
End sub
Here is the Code in Form 2 to raise an event. If the final product selected has the letter "A" in the name it raises the event HasA and passes to the event handler the product name.
Code:
Public Event HasA(Product As String) 'Raise event if selection has an 'a' in the name
Private Sub Form_Close()
If InStr(Me.cmboProducts, "A") > 0 Then
RaiseEvent HasA(Me.cmboProducts)
End If
End Sub
The code in Form 1 to trap this custom event is
Code:
Private WithEvents cmbo As ComboBox
[B]Private WithEvents Frm As Form_form2[/B]
Private Sub cmdOpen_Click()
Set cmbo = Nothing
DoCmd.OpenForm "form2"
Set cmbo = Forms!form2.cmboProducts
Set Frm = Forms!form2
'To ensure that the cmbo raises the afterupdate event need to add "[Event Procedure]" in the event property
cmbo.AfterUpdate = "[Event Procedure]"
End Sub
Private Sub cmbo_AfterUpdate()
'Now can trap an event from a control on another form
Me.txtOutPut = Nz(cmbo, "Nothing Selected")
End Sub
[B]Private Sub Frm_HasA(Product As String)
MsgBox "Final Selection Has An A in the product name"
End Sub[/B]
Any questions or suggestions please provide.
Last edited: