Reference error from custom event (1 Viewer)

Petr Danes

Registered User.
Local time
Today, 01:24
Joined
Aug 4, 2010
Messages
150
I'm trying to use custom events more, and running into some rather odd problems.

Main form has a subform with some associated records. In the main form's OnCurrent event, I call a public routine in the main form's code that does some display housekeeping around the subform's contents. All has worked well for years.

From the main form, a dialog form can be called that affects the set of associated records. When I designed this, I did not know anything about custom events, so I simply requeried the subform when the dialog form closed. Later, I added some flags to requery only when the dialog form had actually made some changes. Again, all worked well.

Now, I replaced the flags and requery on exit with calls to a custom event handler. That event handler is called directly from the dialog form, at the moment when the changes are executed in the dialog form. The call works, but the display housekeeping routine bombs with error 2467, that the requested object does not exist. It does, obviously – the main form is open and the subform is perfectly intact. Some sleuthing uncovered what I consider strange behavior: I need a reference to the main form in my code, despite this code residing entirely within the main form.

That is, I refer to a control on the main form with an expression like cmdUdelatMatrixZeZaznamu for a command button and sfMatrixContainer.Form.Recordset.RecordCount to check the number of records in the subform. That works perfectly when the code is executed from the main form's OnCurrent event, but that same code throws an error when activated by the raised custom event from the dialog form. Some experimenting determined that I have to use a previously set reference to the main form the make this code work from the event call.

Instead of
Code:
cmdUdelatMatrixZeZaznamu
sfMatrixContainer.Form.Recordset.RecordCount
I must use
Code:
ZNForm.cmdUdelatMatrixZeZaznamu
ZNForm.sfMatrixContainer.Form.Recordset.RecordCount
Self-references
Code:
Me.cmdUdelatMatrixZeZaznamu
Me.sfMatrixContainer.Form.Recordset.RecordCount
also do not work – they throw the same error.

Is this normal for custom events? When I call that same routine directly from the dialog form, this does not happen – the references to controls in the main form and subform work normally. However, this requires the dialog form to know how to communicate back with the main form, which is somewhat against what is considered good practice these days. The custom event lets the dialog form simply announce to the world what has happened, and whoever wants can do whatever they want about it. The called routine acts as if it was not in the main form, and does not know about its contents. Requiring such a routine to use external references to its own contents seems rather back-asswards to me.

I suppose one thing I could do would be to move the routine to a separate module, out of the main form, and then external references to the main form would not look so strange, but I don't understand why the external reference is necessary for code inside the main form, and ONLY when called from an event handler, but not when called directly.

Can anyone shed some light on this?
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:24
Joined
May 21, 2018
Messages
8,527
As described this makes no sense. You can trap another objects events such as another form. You just declare a variable using With Events. No need for a custom class to then raise a custom event. Way over complicated.
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:24
Joined
May 21, 2018
Messages
8,527
Need to read

 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Yesterday, 18:24
Joined
Feb 28, 2001
Messages
27,179
Some sleuthing uncovered what I consider strange behavior: I need a reference to the main form in my code, despite this code residing entirely within the main form.

If the sub-form has been Activated (_Activate is an event in the same sequence as _Current) then your program scope is in the sub-form. If you want to use something from the main form, it is Me.Parent.xxx - because Me.xxx refers only to the context of the sub-form.

The call works, but the display housekeeping routine bombs with error 2467, that the requested object does not exist.

And, of course, it DOESN'T exist - in the current scope. Here, I'll grant you that the error message might be considered incomplete. It should have included the "in current scope" disclaimer.

However, this requires the dialog form to know how to communicate back with the main form, which is somewhat against what is considered good practice these days.

This is perhaps arguable. Violate the scoping rules of ANY language and you'll get similar results. "Good practice" in language X might be totally verboten in language Y. "Good practice" is to be aware of the scope rules of the language in which you work.
 

Petr Danes

Registered User.
Local time
Today, 01:24
Joined
Aug 4, 2010
Messages
150
As described this makes no sense. You can trap another objects events such as another form. You just declare a variable using With Events. No need for a custom class to then raise a custom event. Way over complicated.
And what event would I trap? I want this to happen after I finish executing some SQL code that either inserts or updates a specific record in an auxilliary table. That does not raise any event that I know of, hence my use of a custom event.

Also, the way you describe, even if it is possible, would require the main form to know what is happening in the dialog form. And if I have more forms doing similar manipulations, it would have to have an event handler for every possible form that does such work - as I understand it, very much against the philosophy of encapsulation. The custom event is supposed to be an announcement by some code that a specific event just occurred, like the built-in event handlers of controls. The control announces what just happened - broadcasts it to the world, and it's up to others whether they want to react to it.

My dialog form is supposed to work the same way - announce that a table has just been updated. It does not need to know anything about who may or may not be interested, and the main form does not need to know anything about WHO did something, just that it happened. And the link you posted seems to describe exactly that sort of behavior. Am I missing something?
 

Petr Danes

Registered User.
Local time
Today, 01:24
Joined
Aug 4, 2010
Messages
150
If the sub-form has been Activated (_Activate is an event in the same sequence as _Current) then your program scope is in the sub-form. If you want to use something from the main form, it is Me.Parent.xxx - because Me.xxx refers only to the context of the sub-form.
It's not a subform that is raising the event, it's a popup dialog form. The main form contains a subform, and what is filtered and displayed in that subform is what gets changed by code in the dialog form. I want the main form to requery the subform when it hears the news that the table from which the subform draws its records has been updated, via the custom event raised in the dialog form, after it finishes the update.



And, of course, it DOESN'T exist - in the current scope. Here, I'll grant you that the error message might be considered incomplete. It should have included the "in current scope" disclaimer.
How does it not exist? The code is in the main form, the keyword ME returns the proper reference to that main form, and the code runs normally when called via a conventional call from that open dialog form, even though the dialog form is still open. It's only when that EXACT SAME routine is activated by the custom event being raised in that very same dialog form that this behavior occurs.

This is perhaps arguable. Violate the scoping rules of ANY language and you'll get similar results. "Good practice" in language X might be totally verboten in language Y. "Good practice" is to be aware of the scope rules of the language in which you work.
True enough, but there are principles that we've learned over the years that have been shown to have pretty universal application. And the principles I alluded to, specifically encapsulation, certainly do apply to VBA.
 

The_Doc_Man

Immoderate Moderator
Staff member
Local time
Yesterday, 18:24
Joined
Feb 28, 2001
Messages
27,179
How does it not exist? The code is in the main form, the keyword ME returns the proper reference to that main form, and the code runs normally when called via a conventional call from that open dialog form, even though the dialog form is still open. It's only when that EXACT SAME routine is activated by the custom event being raised in that very same dialog form that this behavior occurs.

OK, I'll accept your statement, but Access didn't. The behavior you describe is typical for a scoping error. Where EXACTLY is the code of the custom event? (In which module, more specifically.)

It's not a subform that is raising the event, it's a popup dialog form.

If it is a separate dialog form that is capable of raising an event then it has a code context. Where/how is this dialog form defined?

I have to ask because I found your original description confusing, and that may be why you are getting some of the comments you are getting. After all, proper communication is a key to understanding. Whether it is what you MEANT to say, your description makes me wonder about visibility or scoping issues, and nothing you have responded (so far) has changed that initial diagnosis. I'll believe it could be something else, but not without SOME evidence.

I want this to happen after I finish executing some SQL code that either inserts or updates a specific record in an auxilliary table.

OK, is this SQL statement being executed by SQL Server (or any other external non-Access engine) or is it through normal Access and the ACE engine? If native Access, you could just CALL a subroutine to do what you want without an event because for native Access (ACE or JET engines), this is synchronous. Neither ACE nor JET operates asynchronously with your app. Only an external non-Access engine can run a query that would allow code to run while the query is still running. The only "event" is that you started to execute the next instruction after the SQL execution. Make your subroutine call just after the CurrentDB.Execute or DoCmd.RunSQL statement as appropriate.
 

Cronk

Registered User.
Local time
Today, 09:24
Joined
Jul 4, 2013
Messages
2,772
If I understand the issue, you are trying to initiate from a dialog form, code in another form and subform to execute. The event code routines are not exposed outside that form.

If you want to execute code in another form, you could set the other form's timer event and initiate the code from there.

BTW, to get an accurate recordset count, you need to move clone to the last record of the recordset.
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:24
Joined
May 21, 2018
Messages
8,527
My dialog form is supposed to work the same way - announce that a table has just been updated. It does not need to know anything about who may or may not be interested, and the main form does not need to know anything about WHO did something, just that it happened. And the link you posted seems to describe exactly that sort of behavior. Am I missing something?
Sorry, maybe I do not understand what you are saying, but as written the original thread makes no sense. I am not even sure how object references would even relate to raising and trapping custom events. As I point out in my Event thread many people use the wrong terminology between Events, Event Handlers, and Event Procedures. Maybe that is what is going on. What you say above makes sense, but that is not similar to your original thread.

YES. If a form raises a native event or a custom event another class (form, report, custom) can trap that event. Period. There should be no tightly coupled code. Neither form should reference the other forms objects or procedures. Kind of the whole purpose of Event driven software languages. So that is why I am confused on the discussion about how to reference the objects and events. Not sure how it relates.

That is, I refer to a control on the main form with an expression like cmdUdelatMatrixZeZaznamu for a command button and sfMatrixContainer.Form.Recordset.RecordCount to check the number of records in the subform. That works perfectly when the code is executed from the main form's OnCurrent event, but that same code throws an error when activated by the raised custom event from the dialog form. Some experimenting determined that I have to use a previously set reference to the main form the make this code work from the event call.

In the attached example. I have a calling form. That calls a dialog form. This dialog form exposes a custom event when an animal is chosen.
The calling form traps that event, and prove that it traps the event by announcing that it trapped it. In fact it announces what was chosen. This value is a parameter of the event. Further it demonstrates that it can trap the standard Close event of the dialog form. That seems to be what you are saying you want to do.

Now there is a subtlety. The standard form events can only be referenced by the super class "Form". The custom event can only be trapped through the Sub Class "frmChooseAnimal"

So again, I do not understand how raising and trapping custom events is related in what is described in your original post. If you post your complete code for Instantiating the object references using With Events, the code that raises the custom events, and the custom event handler this may make more sense to me.

If this is not a good demo, explain how to make the demo more representative.

.
 

Attachments

  • CustomEvent.accdb
    1.3 MB · Views: 449

Petr Danes

Registered User.
Local time
Today, 01:24
Joined
Aug 4, 2010
Messages
150
OK, I'll accept your statement, but Access didn't. The behavior you describe is typical for a scoping error. Where EXACTLY is the code of the custom event? (In which module, more specifically.)



If it is a separate dialog form that is capable of raising an event then it has a code context. Where/how is this dialog form defined?

I have to ask because I found your original description confusing, and that may be why you are getting some of the comments you are getting. After all, proper communication is a key to understanding. Whether it is what you MEANT to say, your description makes me wonder about visibility or scoping issues, and nothing you have responded (so far) has changed that initial diagnosis. I'll believe it could be something else, but not without SOME evidence.



OK, is this SQL statement being executed by SQL Server (or any other external non-Access engine) or is it through normal Access and the ACE engine? If native Access, you could just CALL a subroutine to do what you want without an event because for native Access (ACE or JET engines), this is synchronous. Neither ACE nor JET operates asynchronously with your app. Only an external non-Access engine can run a query that would allow code to run while the query is still running. The only "event" is that you started to execute the next instruction after the SQL execution. Make your subroutine call just after the CurrentDB.Execute or DoCmd.RunSQL statement as appropriate.
Ok, sorry - I guess my description was not clear. I'll try again.

Main form is open in single-record form view.
Main form contains subform, in datasheet view, displaying records from an auxilliary table that are linked to the currently visible record in the main form. As main from moves from record to record, this is automatically updated.
Main form also contains command button, which launches a popup dialog form, via code:
Code:
DoCmd.OpenForm "Matrix", acNormal, , , , acDialog
Dialog form does various manipulations of auxilliary table - insert, update, delete.
When such an action is completed, but while the dialog form is still open, I want the main form to update the display in the subform.

If I simply execute a normal subroutine call from the dialog form to a public module in the main form, everything works normally. All references function as expected - the code in the main form knows of itself, knows of its embedded subform, and is able to refer to them without issue.

When I do it by raising an event, the EXACT SAME public module on the main form suddenly does not know any of this. Yes, the event code is a bit more complex:

There is a separate class module that defines the event: cls_ChangeEvents
It defines an event: Public Event MatrixChangeEvent()
and a short routine to raise the event:
Code:
Public Sub MatrixJustChanged()
RaiseEvent MatrixChangeEvent
End Sub

In an ordinary module, I define a global variable for raising all such events:
Code:
Public gbl_evnt_AuxTable As cls_ChangeEvents

In the dialog form, I use this global variable to call this routine after executing the pertinent SQL code:
Code:
gbl_evnt_AuxTable.MatrixJustChanged

The main form has a WithEvents variable defined to listen for the event:
Code:
Private WithEvents ExtTableChange As cls_ChangeEvents

and a routine to handle the event when it is raised:
Code:
Private Sub ExtTableChange_MatrixChangeEvent()
EnableMatrix
End Sub

The routine EnableMatrix is a public module defined within the main form, which does some busy work around the subform. When it is called from the main form's OnCurrent event, it works normally. When it is called from the dialog form via a normal subroutine call, it works normally. When it is called via the chain from raising an event, in that exact same dialog form in the exact same place (after executing the SQL command), that embedded routine suddenly does not know about any of its controls. I have to refer to them via a previously defined variable pointing to the main form. Code using sfMatrixContainer throws the described error. Code using Me.sfMatrixContainer throws the described error. Only code using ZNForm.sfMatrixContainer works properly, where ZNForm is a global public variable, defined in a standard module and set to point to the main form.

All is internal - no connection to SQL Server or any other DB engine. The SQL code is executed via VBA, like:
Code:
CurrentDb.Execute "Delete * From Matrix Where IDCislo = " & CStr(Parent.Parent.txtIDCislo) & " AND KodRod = " & CStr(cboMatrixRod) & " AND KodDruh " & IIf(IsNull(cboMatrixDruh), "Is Null", "= " & CStr(Nz(cboMatrixDruh)))
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:24
Joined
May 21, 2018
Messages
8,527
Still completely confused. Why all the complexity? Why can the dialog form just not raise its own event. What is the need for global variables and another class?
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:24
Joined
May 21, 2018
Messages
8,527
The routine EnableMatrix is a public module defined within the main form, which does some busy work around the subform. When it is called via the chain from raising an event, in that exact same dialog form in the exact same place (after executing the SQL command), that embedded routine suddenly does not know about any of its controls. I have to refer to them via a previously defined variable pointing to the main form. Code using sfMatrixContainer throws the described error.
If this is as you say.
Main form sets a object reference using with events to a custom class that raises an event MatrixChangeEvent
Code:
Private WithEvents ExtTableChange As cls_ChangeEvents
The class raises the event and the main form traps it.
Code:
Private Sub ExtTableChange_MatrixChangeEvent()
  EnableMatrix
End Sub

So that is working.
What I interpret is not working is the procedure EnableMatrix in the main form. This procedure is having problems resolving its own objects, and subform objects. Now that I re read this, I put money on it that what you think is happening is not related.
There is no way that a procedure within a class like EnableMatrix will be unable to resolve other class object references based on how the method was called. Can you show the whole procedure? You are not instantiate multiple instances of the same mainform are you? Still should not matter.
 

Petr Danes

Registered User.
Local time
Today, 01:24
Joined
Aug 4, 2010
Messages
150
Sorry, maybe I do not understand what you are saying, but as written the original thread makes no sense. I am not even sure how object references would even relate to raising and trapping custom events. As I point out in my Event thread many people use the wrong terminology between Events, Event Handlers, and Event Procedures. Maybe that is what is going on. What you say above makes sense, but that is not similar to your original thread.

YES. If a form raises a native event or a custom event another class (form, report, custom) can trap that event. Period. There should be no tightly coupled code. Neither form should reference the other forms objects or procedures. Kind of the whole purpose of Event driven software languages. So that is why I am confused on the discussion about how to reference the objects and events. Not sure how it relates.



In the attached example. I have a calling form. That calls a dialog form. This dialog form exposes a custom event when an animal is chosen.
The calling form traps that event, and prove that it traps the event by announcing that it trapped it. In fact it announces what was chosen. This value is a parameter of the event. Further it demonstrates that it can trap the standard Close event of the dialog form. That seems to be what you are saying you want to do.

Now there is a subtlety. The standard form events can only be referenced by the super class "Form". The custom event can only be trapped through the Sub Class "frmChooseAnimal"

So again, I do not understand how raising and trapping custom events is related in what is described in your original post. If you post your complete code for Instantiating the object references using With Events, the code that raises the custom events, and the custom event handler this may make more sense to me.

If this is not a good demo, explain how to make the demo more representative.

.
I'm kind of new to using custom events, so maybe I didn't explain it very well. Does my explanation to Doc man make it any clearer?

You demo code works perfectly, of coure, but does it not violate the principle of encapsulation? The CallDialog form must know about the ChooseAnimal form, and that an event is being defined by that ChooseAnimal form. What would happen if you had another form also choosing animals? The CallDialog form would also need to know about the contents of that form and define event handlers for that form as well, no?

As for my object references, they of course do not have any bearing on the event apparatus. Or should not, I think. They are simply some of what happens in the routine that the event handler calls. But the routine functions normally when called by a normal subroutine call, yet loses reference to itself and all its contents when called by an event handler.
 

Petr Danes

Registered User.
Local time
Today, 01:24
Joined
Aug 4, 2010
Messages
150
Still completely confused. Why all the complexity? Why can the dialog form just not raise its own event. What is the need for global variables and another class?
Because then the calling from must know about the dialog form, violating encapsulation.
 

Petr Danes

Registered User.
Local time
Today, 01:24
Joined
Aug 4, 2010
Messages
150
If this is as you say.
Main form sets a object reference using with events to a custom class that raises an event MatrixChangeEvent
Code:
Private WithEvents ExtTableChange As cls_ChangeEvents
The class raises the event and the main form traps it.
Code:
Private Sub ExtTableChange_MatrixChangeEvent()
  EnableMatrix
End Sub

So that is working.
What I interpret is not working is the procedure EnableMatrix in the main form. This procedure is having problems resolving its own objects, and subform objects. Now that I re read this, I put money on it that what you think is happening is not related.
There is no way that a procedure within a class like EnableMatrix will be unable to resolve other class object references based on how the method was called. Can you show the whole procedure? You are not instantiate multiple instances of the same mainform are you? Still should not matter.
Below is the entire routine. It is now outside the form, in a standard module, and works fine. Then enclosing With ZNForm is of course necessary when it is in a standard module. When I had it inside the main form, the With ZNForm construct was naturally not necessary. EXCEPT, that it didn't work when called from the event handler, while working when called from anywhere else. Experimenting determined that specifying ZNForm before any reference to controls on the form, including the embedded subform, would make the code work properly, even when called from the event handler. THAT is what I find so confusing.


Code:
Public Sub EnableMatrix()
Const ModID$ = "Form_ZapisNalezu", ProcID$ = "EnableMatrix"
' If matrix type (a parasite), the subform is shown normally.
' If not matrix type, but there are matrix records, subform is shown flat (red border displayed) to indicate error.
' If not matrix type and no matrix records, subform is hidden to let label underneath show through.
' Further, if any matrix records, enable filter command buttons.
' If more than one matrix record, enable up and down buttons.
Dim RC&, JeParazitt As Boolean

' Když se používá hromadná náhrada, žuchne tady pøi události Current, protože nemusí být zrovna v provozu pøíslušný podformuláø.
On Error GoTo Problem
With ZNForm
    gbl_setCtlAbled ctl:=.cmdUdelatMatrixZeZaznamu, stav:=Not IsNull(ZNForm.cboRod)
    RC = .sfMatrixContainer.Form.Recordset.RecordCount
    If IsNull(.cboRod) Then
        gbl_setCtlDisabled ctl:=.cmdMatrixJakoTaxon
    Else
        gbl_setCtlAbled ctl:=.cmdMatrixJakoTaxon, stav:=CurrentDb.OpenRecordset("Select Count(0) From Matrix Where Matrix.KodRod = " & CStr(.cboRod) & " AND Matrix.KodDruh " & IIf(IsNull(.cboDruh), "Is Null", "= " & CStr(Nz(.cboDruh)))).Fields(0) > 0
    End If
    LichRibbon.InvalidateControl tFMgM_tgl_MatrixJakoTaxon
    JeParazitt = JeParazit(Nz(.cboTypUdaje.Column(0)))
    With .sfMatrixContainer
        .enabled = True
        If (JeParazitt = True) And (RC > 0) Then
            If RC > 1 Then
                .SpecialEffect = fmSpecialEffectSunken
            Else
                .SpecialEffect = fmSpecialEffectFlat
            End If
            .Visible = True
            gbl_setCtlEnabled ctl:=ZNForm.cmdUdelatZaznamZMatrix
        Else
            If RC > 1 Then
                .SpecialEffect = fmSpecialEffectFlat
                .Visible = True
            Else
                .Visible = False
            End If
            gbl_setCtlDisabled ctl:=ZNForm.cmdUdelatZaznamZMatrix
        End If
    End With
    If RC > 1 Then
        gbl_setCtlsEnabled arr:=Array(.cmdDeleteMatrix, .cmdVybranyMatrix)
        gbl_setCtlAbled ctl:=.cmdTaxonJakoVybranyMatrix, stav:=IIf(IsNull(DLookup("IDCislo", "ZapisNalezu", "KodRod = " & ZNForm.sfMatrixContainer.Form.txtKodRod & " AND KodDruh " & IIf(IsNull(ZNForm.sfMatrixContainer.Form.txtKodDruh), "Is Null", "= " & ZNForm.sfMatrixContainer.Form.txtKodDruh))), False, True)
    Else
        gbl_setCtlsDisabled arr:=Array(.cmdDeleteMatrix, .cmdTaxonJakoVybranyMatrix, .cmdVybranyMatrix)
    End If
    With LichRibbon
        .InvalidateControl tFMgM_tgl_TaxonJakoMatrix
        .InvalidateControl tFMgM_tgl_MatrixNeniTaxon
        .InvalidateControl tFMgM_tgl_MatrixJakoMatrix
    End With

    If RC > 1 Then
        gbl_setCtlsEnabled arr:=Array(.cmdMatrixUp, .cmdMatrixDn)
    Else
        gbl_setCtlsDisabled arr:=Array(.cmdMatrixUp, .cmdMatrixDn)
    End If
End With
Exit Sub

Problem:
    If Err = 2455 Then
        Exit Sub
    Else
        On Error GoTo ErrHndlr
        Err.Raise vbObjectError
    End If
Exit Sub

ErrHndlr:
ErrMsg ModID, ProcID
End Sub
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:24
Joined
May 21, 2018
Messages
8,527
Because then the calling from must know about the dialog form, violating encapsulation
Sorry, I do not think you understand encapsulation. Every trapped event is a "contract". You will never find an example where the event handler does not have a pointer to the object raising the event. All you did was add an extra link in the chain. Now you have instead tightly coupled a custom class through global variables.
In this updated example I prove that their are not problem with object references if the procedure is called through a trapped custom event.
 

Attachments

  • CustomEvent2.accdb
    1.3 MB · Views: 413

Petr Danes

Registered User.
Local time
Today, 01:24
Joined
Aug 4, 2010
Messages
150
Sorry about the heiroglyphics - this runs on a machine with a Czech OS, and some of that language's special characters do not port.
 

Petr Danes

Registered User.
Local time
Today, 01:24
Joined
Aug 4, 2010
Messages
150
Sorry, I do not think you understand encapsulation. Every trapped event is a "contract". You will never find an example where the event handler does not have a pointer to the object raising the event. All you did was add an extra link in the chain. Now you have instead tightly coupled a custom class through global variables.
In this updated example I prove that their are not problem with object references if the procedure is called through a trapped custom event.
Yes, but doing it as you describe, the calling form must know about EVERY POSSIBLE construct that may raise an event. Doing it my way, yes it is more complex, but the calling form need not know anything about how many other constructs are raising events. Your way, every time I add something that raises an event, I have to modify the main form to take that new construct into account. My way, the main form remains untouched, no matter how many other things I may write. It always reacts to the EVENT, completely oblivious to who raised it.

THAT seems to me to be the essence of encapsulation - various modules need not know about each other.
One raises an event - caring nothing about who may be listening.
Another reacts to an event - caring nothing about how that event happened.
 

MajP

You've got your good things, and you've got mine.
Local time
Yesterday, 19:24
Joined
May 21, 2018
Messages
8,527
My way, the main from remains untouched, no matter how many other things I may write. It always reacts to the EVENT, completely oblivious to who raised it.
No that is not true. You just added another class module in the middle to raise the event, but you are hard coding tightly coupling it with the global variables. This is a poor design. I will say it one more time, every event handler has a contract with the thing raising the event. You are just doing it through a class. It is an unnecessary chain.
So instead of having each form raise its own events you simulate this by calling a procedure or setting a global variable. You just centralized the event calling. THIS IS NOT encapsulation. Encapsulation is about protection of the objects. You protect the inner working and make available public and methods and variables. This is the opposite especially with all these global variables.

If I had 10 forms each changing animals, I would have ten object variables and 10 event handlers. I would not tightly couple my ten forms to a single custom class to raise a single event. That is convoluted and violates good coding.
 

Users who are viewing this thread

Top Bottom