Event Handling...and ByRef Passing...

JaedenRuiner

Well-known member
Joined
Aug 13, 2007
Messages
340
Programming Experience
10+
On my form (AdminForm) I have an Object declared "WithEvents" which listens for a DB Connection Event within my internal class. During the Disconnect/Reconnect methods that attach my wrapper class to a database connection, a specific event is triggering only half of the time.

The Logon method (a global method that opens the Login form and executes the connection) receives this object from the AdminForm as a ByRef parameter, allowing me to Create the object and open the connection, at which point all the other event handling is working except this one event.

VB.NET:
[U]AdminForm.vb[/U]
private WithEvents _RexCon as DBWrapper

public sub _RexCon_ConnectionEvent(...) handles _RexCon.ConnectionEvent
  'code
end sub

public Sub Reconnect()
  if not My.Application.DoLogon(_RexCon) then
     Application.Exit
  end if
end sub

[U]ApplicationEvents.vb[/U]
public Sub DoLogon(byref RexCon as DBWrapper)
   if LoginForm.ShowDialog(...) then
     RexCon = new DBWrapper(...)
     RexCon.Connect(...)
   end if
end sub

[U]DBWrapper[/U]
private withevents _conn as SqlConnection

public sub Connect(...)
   _conn.Open()
end sub

public sub _conn_StateChange(...) handles _conn.StateChange
  RaiseEvent ConnectionEvent(...)
end sub

This is very quick pseudo-code, but it is clear enough. The AdminFrom execute the ReConnect() method, which calls the DoLogon Method in the App Events Global file. The DoLogon method gets the login info from the login form and creates the new DBWrapper class, and then executes teh DBWrapper.Connect. When the Connect method fires it opens the connection which calls the SqlConnection.StateChange Event (this all fires as i've stepped through it), however when it comes to the line in the StateChange event handler that raises the DBWrapper.ConnectionEvent Event, that event does not trigger back to the AdminForm ConnectionEvent handler for the Rexcon object. As I am passing this all via ByRef and reference passing, I would expect the with events to maintain throughout.

Does the "New DBWrapper()" need to take place before the DoLogon event is called to connect?

thanks
 
I would also think that the Handler stays with the private Object...
Yes, it does, sort of. The Handler Binding is done on the private level, but once added, the handler will trigger from anywhere. Thus I found instead of Creating the Object within the DoLogon method, I create it before.

I was trying to avoid the "Create-then-destory-if-fail" concept, but cest-la-vie.
Now I simply do:
VB.NET:
_rexCon = new DBWrapper()
if Not My.Application.DoLogon(_rexcon) then
  _rexcon.dispose()
end if

And that works every time on all the events. What I found was that, and I do understand this logically on how method addresses are associated with any object (regardless of language), is that the "WithEvents" does a form of late-binding of the method addresses on the private level at creation, so, when the object is instantiated, as part of the creation all the event handlers are automatically added. however, since VB doesn't handle reference parameters the same, the "new DbWrapper" line in the dologon() method was not associated immediately with the "withevents" declared object , so the event handlers are added to the the object, but not until the object is returned from the DoLogon() Method, and only because the DoLogon() method is not privy to the private Class Object it is only receiving the reference.

Basically, the way Delphi / C++ does it:
VB.NET:
X = Object, Address of X = 0x12345678

MyProcedure(byref Obj as Object)

MyProcedure(X)

When I pass X to MyProcedure, my procedure receives the 0x12345678 and therefore, when I set Obj equal to anything (obj = New Whatever) in C++/Delphi I can directly read the memory address:
VB.NET:
Pascal Watch:
Integer(Pointer($012345678)^)
And i would see 0 for Nothing (Nil/Null), or a value for address of the Newly created Whatever() object. VB doesn't exactly handle the Byref in the same manner, with more of an "assignment" after-the-fact, which isn't that big of a deal when understanding what VB is good for. Regardless, I realize now that the ByRef as a complete non-issue since the problem was with the WithEvents keyword. WithEvents is not even possible in Delphi/C++ languages, so were I to write this same methodology in those languages, to receive the event trigger from a created object in a separate method, after creation I would have to Assign the Event Property to the event Method Address anyway. The WithEvents is a VB special coolness that allows one to assign 12 event handlers to one object without having to execute "Addhandler" for each event method. So within the private scope of the form object, when a "WithEvents" field is created, the compiler automatically adds all event methods that are declared as "Handles MyObj.Event", and thus once created, no matter where that reference goes, the events will be triggered, however, that WithEvents effect ONLY takes places within the private scope of the owning object. Basically, I was trying to take a VB special ability and see how far I could push it. *cheezygrin* Obviously, I went one step too far.

Thanks Anyway, but I got it working. :)
 
Last edited:
Back
Top