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: