locked
How do I detect if an event has been cast to a procedure yet? RRS feed

  • Question

  • WHAT I HAVE:

    Visual Basic 2015, WinForms

    MY PROBLEM:

    I know that AddHandler and RemoveHandler can be used to wire or un-wire an event to a procedure. The problem is, if an event is already wired when AddHandler is invoked, the event is then multi-cast to 2 or more procedures. (I don't know what happens if RemoveHandler is used on a non-existent wire-up.) Is there a way to determine at run time whether or not an event has been wired up to a procedure? Something like this:

    Public Function IsWiredUp(Event, Procedure) As Boolean

    ' determine if Procedure catches Event ... End Function

    with the host code like this:

    '   add event-handler if necessary
    If Not IsWiredUp(object.event, AddressOf procedure) Then
       AddHandler object.event, AddressOf procedure
    End If
    '   do other stuff
    ...
    '   remove event-handler if necessary
    If IsWiredUp(object.event, AddressOf procedure) Then
       RemoveHandler object.event, AddressOf procedure
    End If
    I'd like an answer ASAP!

    Robert Gustafson




    Thursday, October 5, 2017 9:54 PM

Answers

  • Let me see if I'm getting this right. The above RemoveHandler/AddHandler code I wrote above should do the following, right? (Just a yes or no answer will do.)

    1. If the event isn't already wired to the procedure, it'll wire it up for the first time.
    2. If it is already wired up, it'll un-wire it then re-wire it, so that the same procedure doesn't fire an extra time.

    Robert Gustafson


    Correct

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, October 5, 2017 11:06 PM

All replies

  • Robert,

    An event is never cast, but I think I understand what you're asking.

    I don't know of a way to see if a subscriber of an event has "acted on" that event being raised, but I think the answer to what you're trying to do is in your embedded question of "I don't know what happens if RemoveHandler is used on a non-existent wire-up."

    The answer is that it's harmless:

    Option Strict On
    Option Explicit On
    Option Infer Off
    
    Public Class Form1
        Private Sub _
            Form1_Load(sender As System.Object, _
                       e As System.EventArgs) _
                       Handles MyBase.Load
    
            Dim tb As New TextBox _
                With {.Size = New Size(100, 20), _
                      .Location = New Point(100, 50)}
    
            RemoveHandler tb.TextChanged, AddressOf TextBox_TextChanged
            RemoveHandler tb.TextChanged, AddressOf TextBox_TextChanged
            RemoveHandler tb.TextChanged, AddressOf TextBox_TextChanged
    
            Me.Controls.Add(tb)
    
        End Sub
    
        Private Sub _
            TextBox_TextChanged(sender As System.Object, _
                                e As System.EventArgs)
    
            Stop
    
        End Sub
    End Class

    It's ignored; no "AddHandler" was ever in there so the RemoveHandler is ignored.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    • Proposed as answer by IronRazerz Thursday, October 5, 2017 11:03 PM
    Thursday, October 5, 2017 10:14 PM
  • The real question is, how do I know if an event is already being caught by a procedure? I don't want to accidentally wire up the same event to the same procedure multiple times, resulting in multiple executions. And there are times when it isn't easy to keep track of this stuff manually. You didn't answer the main question!

    Robert Gustafson


    Thursday, October 5, 2017 10:35 PM
  • The real question is, how do I know if an event is already being caught by a procedure? I don't want to accidentally wire up the same event to the same procedure multiple times, resulting in multiple executions. And there are times when it isn't easy to keep track of this stuff manually.

    Robert Gustafson

    I don't know that you can, but if you're at all in doubt, use RemoveHandler. If one has been created, it's removed; if it's not there, it's harmless.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, October 5, 2017 10:38 PM
  • In other words, do the following:

    RemoveHandler object.event, AddressOf procedure 'redundant if not already wired

    AddHandler object.event, AddressOf procedure

    And this will prevent multi-casting, right?


    Robert Gustafson


    Thursday, October 5, 2017 10:43 PM
  • In other words, do the following:

    RemoveHandler object.event, AddressOf procedure 'redundant if not already wired

    AddHandler object.event, AddressOf procedure

    And this will prevent multi-casting, right?


    Robert Gustafson


    Multicasting is when there's more than one eventhandler subscribed to an event, so "no" would be the answer there.

    The following is a dumb revision of what I posted earlier but hopefully it'll make my point:

    Option Strict On
    Option Explicit On
    Option Infer Off

    Public Class Form1
        Private Sub _
            Form1_Load(sender As System.Object, _
                       e As System.EventArgs) _
                       Handles MyBase.Load

            Dim tb As New TextBox _
                With {.Size = New Size(100, 20), _
                      .Location = New Point(100, 50)}

            AddHandler tb.TextChanged, AddressOf TextBox_TextChanged
            AddHandler tb.TextChanged, AddressOf DoSomethingElse

            RemoveHandler tb.TextChanged, AddressOf TextBox_TextChanged

            Me.Controls.Add(tb)

        End Sub

        Private Sub _
            TextBox_TextChanged(sender As System.Object, _
                                e As System.EventArgs)

            Stop

        End Sub

        Private Sub _
            DoSomethingElse(sender As System.Object, _
                            e As System.EventArgs)

            Stop

        End Sub
    End Class

    Did the eventhandler method still respond to "DoSomethingElse"?

    Yes - I didn't remove that one.


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, October 5, 2017 10:51 PM
  • I'm sorry, I used the wrong terminology. My question was, if I use RemoveHandler, followed by AddHandler, on an event-procedure combination (which may or may not already be set up), that will prevent the (same) procedure from executing multiple times, right? Once again:

    RemoveHandler object.event, AddressOf procedure

    AddHandler object.event, AddressOf procedure



    Robert Gustafson

    Thursday, October 5, 2017 10:56 PM
  • I'm sorry, I used the wrong terminology. My question was, if I use RemoveHandler, followed by AddHandler, on an event-procedure combination (which may or may not already be set up), that will prevent the (same) procedure from executing multiple times, right? Once again:

    RemoveHandler object.event, AddressOf procedure

    AddHandler object.event, AddressOf procedure



    Robert Gustafson

    That would work fine, but just to make sure that we're connecting here, I modified it again (now it's really dumb!):

    Option Strict On
    Option Explicit On
    Option Infer Off
    
    Public Class Form1
        Private Sub _
            Form1_Load(sender As System.Object, _
                       e As System.EventArgs) _
                       Handles MyBase.Load
    
            Dim tb As New TextBox _
                With {.Size = New Size(100, 20), _
                      .Location = New Point(100, 50)}
    
            AddHandler tb.TextChanged, AddressOf TextBox_TextChanged
            AddHandler tb.TextChanged, AddressOf DoSomethingElse
            AddHandler tb.TextChanged, AddressOf TextBox_TextChanged
    
            RemoveHandler tb.TextChanged, AddressOf TextBox_TextChanged
    
            Me.Controls.Add(tb)
    
        End Sub
    
        Private Sub _
            TextBox_TextChanged(sender As System.Object, _
                                e As System.EventArgs)
    
            Stop
    
        End Sub
    
        Private Sub _
            DoSomethingElse(sender As System.Object, _
                            e As System.EventArgs)
    
            Stop
    
        End Sub
    End Class

    I can't imagine why someone would do that but if they did then both eventhandler subs will respond.

    Three were added but only one was removed.

    Make sense?


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, October 5, 2017 10:59 PM
  • I'm sorry, I used the wrong terminology. My question was, if I use RemoveHandler, followed by AddHandler, on an event-procedure combination (which may or may not already be set up), that will prevent the (same) procedure from executing multiple times, right? Once again:

    RemoveHandler object.event, AddressOf procedure

    AddHandler object.event, AddressOf procedure



    Robert Gustafson


     That is correct.

    If you say it can`t be done then i`ll try it

    Thursday, October 5, 2017 11:02 PM
  • Let me see if I'm getting this right. The above RemoveHandler/AddHandler code I wrote above should do the following, right? (Just a yes or no answer will do.)

    1. If the event isn't already wired to the procedure, it'll wire it up for the first time.
    2. If it is already wired up, it'll un-wire it then re-wire it, so that the same procedure doesn't fire an extra time.

    Robert Gustafson

    Thursday, October 5, 2017 11:05 PM
  • Let me see if I'm getting this right. The above RemoveHandler/AddHandler code I wrote above should do the following, right? (Just a yes or no answer will do.)

    1. If the event isn't already wired to the procedure, it'll wire it up for the first time.
    2. If it is already wired up, it'll un-wire it then re-wire it, so that the same procedure doesn't fire an extra time.

    Robert Gustafson


    Correct

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, October 5, 2017 11:06 PM
  • Hello,

    Here is a proof of concept that works in it will locate a Click event for Button1 both via AddHandler in tangent with lambda which has not event name and also via the standard Handles clause. But just because it can be done does not mean it should be done. I've always have use RemoveHandler prior to an AddHandler (and that was rare) to ensure there were not multiple events for an object.

    So here we go, straight down deep into Reflection. There are different permutations to try out too. 

    Public Class Form1
        Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
            AddHandler Button1.Click,
              Sub()
                  MessageBox.Show("Button1.Clicked 1")
              End Sub
        End Sub
        Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
            Dim FI_EventClick As Reflection.FieldInfo =
                GetType(Control).GetField("EventClick", CType(32 Or 8, Reflection.BindingFlags))
    
            'This is the Key for the Event Click in the EventHandlerList
            Dim oClick As Object = FI_EventClick.GetValue(Button1)
            Dim ComponentType As Type = GetType(ComponentModel.Component)
    
            'Non-Public Instance
            Dim FI_Events As Reflection.FieldInfo = ComponentType.GetField("events", CType(32 Or 4, Reflection.BindingFlags))
            Dim Events As System.ComponentModel.EventHandlerList
    
            'This is the Button1 EventHandlerList
            Events = CType(FI_Events.GetValue(Button1), ComponentModel.EventHandlerList)
    
            'This is the Click event delegate
            Dim Handlers As EventHandler = CType(Events.Item(oClick), EventHandler)
            If Handlers IsNot Nothing Then
                ' This is the delegate invocation list for the Click event
                Dim InvList() As [Delegate] = Handlers.GetInvocationList
                For Each method As [Delegate] In InvList
                    If method.Method.Name.Contains("Lambda$") Then
    
                        ' Remove the Lambda handler from the event
                        RemoveHandler Button1.Click, CType(method, Global.System.EventHandler)
    
                        Exit Sub
                    End If
                Next
            Else
                AddHandler Button1.Click,
                  Sub()
                      MessageBox.Show("Clicked")
                  End Sub
            End If
        End Sub
        Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
            MessageBox.Show("Button1.Clicked 2")
        End Sub
    End Class
    


    Please remember to mark the replies as answers if they help and unmark them if they provide no help, this will help others who are looking for solutions to the same or similar problem. Contact via my Twitter (Karen Payne) or Facebook (Karen Payne) via my MSDN profile but will not answer coding question on either.
    VB Forums - moderator
    profile for Karen Payne on Stack Exchange, a network of free, community-driven Q&A sites

    Thursday, October 5, 2017 11:06 PM
  • Let me see if I'm getting this right. The above RemoveHandler/AddHandler code I wrote above should do the following, right? (Just a yes or no answer will do.)

    1. If the event isn't already wired to the procedure, it'll wire it up for the first time.
    2. If it is already wired up, it'll un-wire it then re-wire it, so that the same procedure doesn't fire an extra time.

    Robert Gustafson

     Again,  that is correct.

     Although,  if it is being raised multiple times,  there may be other reasons for that.


    If you say it can`t be done then i`ll try it


    • Edited by IronRazerz Thursday, October 5, 2017 11:08 PM
    • Marked as answer by RobertGustafson Thursday, October 5, 2017 11:10 PM
    • Unmarked as answer by RobertGustafson Thursday, October 5, 2017 11:14 PM
    Thursday, October 5, 2017 11:07 PM
  • Robert,

    I went through all that and you marked someone else as the answerer??


    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, October 5, 2017 11:12 PM
  •  Robert,  I did not really answer your question so,  you should un-mark my post as the answer and mark Frank's post as the answer if that worked for you.  8)

    If you say it can`t be done then i`ll try it

    Thursday, October 5, 2017 11:13 PM
  • It doesn't matter who's marked so long as the answer's the same, and it's right. (Does it?)

    Robert Gustafson

    Thursday, October 5, 2017 11:14 PM
  • It doesn't matter who's marked so long as the answer's the same, and it's right. (Does it?)

    Robert Gustafson


    ...let's move on

    "A problem well stated is a problem half solved.” - Charles F. Kettering

    Thursday, October 5, 2017 11:15 PM
  • Is there a way to determine at run time whether or not an event has been wired up to a procedure?

    A delegate exposes the GetInvocationList method that allows you to see the methods invoked for that delegate.

    https://msdn.microsoft.com/en-us/library/system.delegate.getinvocationlist%28v=vs.110%29.aspx?

    Thursday, October 5, 2017 11:41 PM