jwcolby
jwcolby at colbyconsulting.com
Mon Jun 20 13:55:51 CDT 2011
> For a separate form, first determine if the form is open:
Yes, but that is so... Access 2 ish. ;)
Raising and sinking events solves this problem nicely. And I don't have to do all the "is this
open, and if so then do this exact thing..." stuff.
To see this all work just cut and paste the following into a pair of classes and a module and tun
the test function.
Create a class called dclsMsg and put the following into it.
Option Compare Database
Option Explicit
Public Event Message(varFrom As Variant, varTo As Variant, _
varSubj As Variant, varMsg As Variant)
Public Event MessageSimple(varMsg As Variant)
Function Send(Optional varFrom As Variant, Optional varTo As Variant, _
Optional varSubj As Variant, Optional varMsg As Variant)
RaiseEvent Message(varFrom, varTo, varSubj, varMsg)
End Function
Function SendSimple(varMsg As Variant)
RaiseEvent MessageSimple(varMsg)
End Function
Create a class called clsMsgReceiver and place the following into it:
Option Compare Database
Option Explicit
Dim WithEvents mclsMsg As dclsMsgClean
Private Sub Class_Initialize()
Set mclsMsg = cMsg() 'Get a pointer to the public message class
End Sub
Private Sub mclsMsg_Message(varFrom As Variant, varTo As Variant, varSubj As Variant, varMsg As Variant)
Dim strMsgStuff As String
On Error Resume Next
strMsgStuff = "Hi, this is MsgRcvr. My message is " & vbCrLf
strMsgStuff = strMsgStuff & "From: " & varFrom & vbCrLf
strMsgStuff = strMsgStuff & "To: " & varTo & vbCrLf
strMsgStuff = strMsgStuff & "Subj: " & varSubj & vbCrLf
strMsgStuff = strMsgStuff & "Msg: " & varMsg
MsgBox strMsgStuff
End Sub
Private Sub mclsMsg_MessageSimple(varMsg As Variant)
MsgBox "Hi, this is MsgRcvr. My received message is: " & varMsg
End Sub
Create a module called basMsg and put the following into it.
Option Compare Database
Option Explicit
Private mclsMsg As dclsMsgClean
Private mclsMsgRcvr As clsMsgReceiver
Function cMsg() As dclsMsgClean
If mclsMsg Is Nothing Then
Set mclsMsg = New dclsMsgClean
Set mclsMsgRcvr = New clsMsgReceiver
End If
Set cMsg = mclsMsg
End Function
Function mMsgTerm()
Set mclsMsg = Nothing
End Function
Function mTest()
cMsg.SendSimple "VolID=1;"
cMsg.Send "mTest", , "VolID=1;"
cMsg.Send "mTest", "frmMsgTest", "VolID=1;"
cMsg.Send "mTest", "frmMsgTest", "VolID", 1
End Function
Now run mTest and watch what happens.
Now step through mtest and watch what happens.
Now you can dimension the messageclass in a form (see the header of clsMsgReceiver), get the pointer
to the global message class (see the Class_Initialize) and sink messages in any form (see
mclsMsg_Messge()).
Why do you do this?
Because the message sender (mTest in this case) can send messages and not care who is actually
receiving them. All it needs to know is that it needs to send a message. No "is form xyz open"
kind of stuff.
FrmXYZ can now sink events (messages in this case) and check whether it wants to actually process
the message. It can look for messages with its own name in the "To" field, or it can check the
subject to see if it is a subject that it wants to process etc.
FrmABC can also sink events (messages in this case). It can do the same thing, only handle messages
sent "To" that form, or process all messages "from" a specific "sender" etc.
Just remember that the sender doesn't care whether the recipient is listening.
Now, let's take my actual case:
I have a volunteer form with a subform where the user adds and deletes cities that that volunteer
wants to see locations and meetings in.
In the Cities subform I (literally) do the following:
Private Sub Form_AfterDelConfirm(Status As Integer)
cMsg.send "sfrmVolunteerCities", "frmVolunteers", "RefreshLists"
End Sub
Private Sub Form_AfterUpdate()
cMsg.send "sfrmVolunteerCities", "frmVolunteers", "RefreshLists"
End Sub
So if I update the form I send a message saying "refreshLists", and if I delete a record I send the
same message.
As it happens frmVolunteers is the parent of sfrmVolunteerCities, but that really doesn't matter.
In frmVolunteers I dimension the message class withevents and then set it to the global message
class pointer:
Private WithEvents mcMsg As dclsMsg
Private Sub Form_Open(Cancel As Integer)
Set mcMsg = cMsg()
End Sub
I then sink the event:
Private Sub mcMsg_Message(varFrom As Variant, varTo As Variant, varSubj As Variant, varMsg As Variant)
If varFrom = "sfrmVolunteerCities" Then
If varTo = "frmVolunteers" Then
If varSubj = "RefreshLists" Then
lstCities.Requery
lstMeetings.Requery
End If
End If
End If
End Sub
In this case I am getting *very* specific but in the end all I am really doing is checking that the
message is for me and then refreshing two lists. These lists display all the locations and meetings
in the cities I am adding in the subform.
Now... I *could* already have another form open which has some combos on it that also need to be
refreshed...
in those two subforms I do the same thing:
Private WithEvents mcMsg As dclsMsg
Private Sub Form_Open(Cancel As Integer)
Set mcMsg = cMsg()
End Sub
and then sink the event:
Private Sub mcMsg_Message(varFrom As Variant, varTo As Variant, varSubj As Variant, varMsg As Variant)
If varFrom = "sfrmVolunteerCities" Then
If varSubj = "RefreshLists" Then
cboMeeting.Requery
End If
End If
End Sub
Notice that in this case I ignore the To: and only filter on who the message is from and the
subject. If it is from the right place and is the right subject then I requery the combo.
The key information here is that:
1) Events are raised by the message class and pass parameters to the message sink
2) If there is no recipient, no harm no foul.
3) If there is a recipient, then the recipient decides what to do.
4) The sender does not have to check whether the recipient is open, or write code in the sender
specific to what the recipient is supposed to be doing.
5) I can have no code actually open and sinking the message or I can have 20 places sinking the
messages. In any case, the *recipient* decides what to do with the message, *not* the sender.
In my case, each and every recipient needs to do something different but similar. Requery
something. A pair of lists in one form, a different combo in each of two other forms. The sender
just says "I modified the list of cities". The recipients says "OK, I need to do this thing when
the list of cities changes" and then does that thing.
John W. Colby
www.ColbyConsulting.com
On 6/20/2011 11:06 AM, Dan Waters wrote:
> Hi John,
> For a separate form, first determine if the form is open: