By using this site, you agree to our updated Privacy Policy and our Terms of Use. Manage your Cookies Settings.
459,458 Members | 1,215 Online
Bytes IT Community
+ Ask a Question
Need help? Post your question and get tips & solutions from a community of 459,458 IT Pros & Developers. It's quick & easy.

Bug? Events from private member object still firing after it has been set to Nothing?

P: n/a

I sometimes use delegates for broadcasting
"StateChanged" events, i.e. if I have multiple forms
and/or controls that need updating at the same time
as the result of a change in a global/common object,
I keep local references to this object in each UI
object, e.g.

Private WithEvents _tools As RepeatTools

and catch messages in an event handler like this:

Private Sub _tools_StateChanged(ByVal sender As Object, ByVal
e As System.EventArgs) Handles _tools.StateChanged
If Me.AcceptEvents Then
Try
DisplayProperties(sender)
Finally
Me.EnableEvents()
End Try
End If
End Sub

In the past, I have had problems with _tools_StateChanged
events still firing after a form has been closed - as if parts of
the form is still alive somewhere. Of course, once the event
fires and code attempts to access the now disposed controls
on the form, an exception is thrown.

Until now, I have solved this by adding something like this:

Private Sub frmRepeatPreview_FormClosing(ByVal sender As
Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles
Me.FormClosing
_tools = Nothing
End Sub

to ensure that _tools would no longer fire any events in that
form.

HOWEVER: Now I have encountered a situation where
_tools_StateChanged is firing even though _tools has been
set to Nothing, i.e. to fix it, I had to insert a "sentinel":

Private Sub _tools_StateChanged(ByVal sender As Object, ByVal
e As System.EventArgs) Handles _tools.StateChanged
If _tools Is Nothing Then
Return '<<<<<< Yes, we actually end up here!
End If

If Me.AcceptEvents Then
Try
DisplayProperties(sender)
Finally
Me.EnableEvents()
End Try
End If

End Sub

And now everything works, but I have plenty of code like
this without such a check and I am concerned that something
else might fail someday, so rather than hunt through my code
to apply the same fix everywhere, could someone please explain
to me what it is I do not understand and what I need to do to
ensure that such delegates stop firing events?

TIA,

Joergen Bech

Mar 27 '08 #1
Share this Question
Share on Google+
4 Replies


P: n/a
Hello Joergen,

Not knowing for certain how things work under the covers, this may be incorrect.

It is simply an calculated guess.

I do not know how handles works internally but let us suppose that it Translates
to an AddHandler call early on in the construction of the object.

We can then suppose that since the handler is hooked up to the instance of
the object then your setting your reference to nothing does not allow the
object to be disposed and so it remains able to generate events.

If I am correct, you could replace your Handles with an addhandler call and
call remove handler when you set _tools = nothing.

You might be able to call removehandler anyway asthough you had called addhandlerwhich
might disconnect the handles keyword.

As I say all of this is (slightly calculated) guesswork.

Perhaps it will help.

--
Rory
Mar 27 '08 #2

P: n/a
Hi Joergen,

Just reading the responses to your post: seems there's a lot of confusion
out there as to what WithEvents and declarative event handling in VB does.
Hopefully this will shed some light upon that for the other folks here.....

When you declare a field as WithEvents, VB actually creates a Property with
that name, and a backing field with the same name prefixed by an
underscore... in this case _tools would be the property name and it would
have a backing field __tools. In the property Set, if __tools is not
nothing, then any events declared declaratively via the Handles statement
will be unwired for the reference. (RemoveHandler), and if the new value is
not nothing, then the events will be wired up.

So given this, your setting _tools = Nothing will unwire the event handlers.
If however you wrote __tools = Nothing, you would not unwire the event
handlers, and in fact you would prevent VB from being able to unwire. The
extra _ can be an un-doing of the best of code ;)

You also may be experiencing race conditions in that even though you have
attempted to unwire, an event invocation may already be queued. This is
unlikely, but if it is just one extra event immediately after the form is
closed, it can happen.



"Joergen Bech" <jb***@post1.tele.dkwrote in message
news:g8********************************@4ax.com...
>
I sometimes use delegates for broadcasting
"StateChanged" events, i.e. if I have multiple forms
and/or controls that need updating at the same time
as the result of a change in a global/common object,
I keep local references to this object in each UI
object, e.g.

Private WithEvents _tools As RepeatTools

and catch messages in an event handler like this:

Private Sub _tools_StateChanged(ByVal sender As Object, ByVal
e As System.EventArgs) Handles _tools.StateChanged
If Me.AcceptEvents Then
Try
DisplayProperties(sender)
Finally
Me.EnableEvents()
End Try
End If
End Sub

In the past, I have had problems with _tools_StateChanged
events still firing after a form has been closed - as if parts of
the form is still alive somewhere. Of course, once the event
fires and code attempts to access the now disposed controls
on the form, an exception is thrown.

Until now, I have solved this by adding something like this:

Private Sub frmRepeatPreview_FormClosing(ByVal sender As
Object, ByVal e As System.Windows.Forms.FormClosingEventArgs) Handles
Me.FormClosing
_tools = Nothing
End Sub

to ensure that _tools would no longer fire any events in that
form.

HOWEVER: Now I have encountered a situation where
_tools_StateChanged is firing even though _tools has been
set to Nothing, i.e. to fix it, I had to insert a "sentinel":

Private Sub _tools_StateChanged(ByVal sender As Object, ByVal
e As System.EventArgs) Handles _tools.StateChanged
If _tools Is Nothing Then
Return '<<<<<< Yes, we actually end up here!
End If

If Me.AcceptEvents Then
Try
DisplayProperties(sender)
Finally
Me.EnableEvents()
End Try
End If

End Sub

And now everything works, but I have plenty of code like
this without such a check and I am concerned that something
else might fail someday, so rather than hunt through my code
to apply the same fix everywhere, could someone please explain
to me what it is I do not understand and what I need to do to
ensure that such delegates stop firing events?

TIA,

Joergen Bech
Mar 27 '08 #3

P: n/a

Thank you. I'll try the explicit Add/Remove approach and remove
the WithEvents keyword so I can control the process.

It is probably a bad idea to keep the WithEvents keyword and use
AddHandler "just in case". Unclean and unsafe in my eyes.

Regards,

Joergen Bech

On Thu, 27 Mar 2008 12:48:02 +0000 (UTC), Rory Becker
<ro********@newsgroup.nospamwrote:
>Hello Joergen,

Not knowing for certain how things work under the covers, this may be incorrect.

It is simply an calculated guess.

I do not know how handles works internally but let us suppose that it Translates
to an AddHandler call early on in the construction of the object.

We can then suppose that since the handler is hooked up to the instance of
the object then your setting your reference to nothing does not allow the
object to be disposed and so it remains able to generate events.

If I am correct, you could replace your Handles with an addhandler call and
call remove handler when you set _tools = nothing.

You might be able to call removehandler anyway asthough you had called addhandlerwhich
might disconnect the handles keyword.

As I say all of this is (slightly calculated) guesswork.

Perhaps it will help.
Mar 27 '08 #4

P: n/a

On Fri, 28 Mar 2008 00:47:26 +1100, "Bill McCarthy" <Bi**@NOSPAM.com>
wrote:
>Hi Joergen,

Just reading the responses to your post: seems there's a lot of confusion
out there as to what WithEvents and declarative event handling in VB does.
Hopefully this will shed some light upon that for the other folks here.....

When you declare a field as WithEvents, VB actually creates a Property with
that name, and a backing field with the same name prefixed by an
underscore... in this case _tools would be the property name and it would
have a backing field __tools. In the property Set, if __tools is not
nothing, then any events declared declaratively via the Handles statement
will be unwired for the reference. (RemoveHandler), and if the new value is
not nothing, then the events will be wired up.
I took a closer look using Reflector and you are right (which I don't
have to tell you). For others reading this thread, it looks like this:

Private Overridable Property _tools As RepeatTools
Get
Return Me.__tools
End Get
Set(ByVal WithEventsValue As RepeatTools)
If (Not Me.__tools Is Nothing) Then
RemoveHandler Me.__tools.StateChanged, New
StateChangedEventHandler(AddressOf Me._tools_StateChanged)
End If
Me.__tools = WithEventsValue
If (Not Me.__tools Is Nothing) Then
AddHandler Me.__tools.StateChanged, New
StateChangedEventHandler(AddressOf Me._tools_StateChanged)
End If
End Set
End Property

and

"_tools = Nothing"

actually becomes

"Me._tools = Nothing"

which means that the private property setter is called and the
event handler is, in fact, explicitly removed immediately, just by
using "_tools = Nothing".

This also means that removing the WithEvents keyword and adding/
removing event handlers explicitly is not going to make a bit of
difference if everything else is kept the same (i.e. if I keep the
same flow of statements/events).
>So given this, your setting _tools = Nothing will unwire the event handlers.
If however you wrote __tools = Nothing, you would not unwire the event
handlers, and in fact you would prevent VB from being able to unwire. The
extra _ can be an un-doing of the best of code ;)
I can safely say that although I start all my non-public member
variables with an underscore, there are no double underscores
in my source. I would not do such a thing :)
>You also may be experiencing race conditions in that even though you have
attempted to unwire, an event invocation may already be queued. This is
unlikely, but if it is just one extra event immediately after the form is
closed, it can happen.
You hit the nail spot on the head with that last comment.

The form/member destruction does indeed happen in response to a
StateChanged event happening for a reference to the same object
but in another form. That other form then closes the form we are
talking about, leaving a queued event that insists on firing in
limbo.

My original "sentinel" solution takes care of the problem, but
the proper solution would be to take care of the architectural flaw
that allows this to happen.

All my fault.

Regards,

Joergen Bech

Mar 27 '08 #5

This discussion thread is closed

Replies have been disabled for this discussion.