locked
how to remove all handler from an event of form using VB.Net? RRS feed

  • Question

  • I am working on a window application (written using Vb.net).In the main form Load event another form 'frmcrew_managment' is also loaded.In this stage for RefreshClick event of Main form attaches 'Refreshadata' method ( handler) of 'frmcrew_managment' . As a result after the main form is loaded it's RefreshClick Event has the address of method of 'frmcrew_managment'. Now in the main form one of Menu options is OpenAdjustment (frmOpenAdjustment ) . So onclick of OpenAdjustment option, in it's form load (for frmOpenAdjustment ) I need to attach RefreshGriddata Method (of frmOpenAdjustment) to RefreshClick event of Main Form sothat when user clicks Refresh on main screen RefreshGriddata Method of frmOpenAdjustment is called. But now what is happening Refreshadata of frmcrew_managment is also getting called. So to solve this I need to remove all event handler from RefreshClick event of main Form before adding event handler RefreshGriddata of frmOpenAdjustment . So what is the way to removed all event handler from an event (RefreshClick )of main form?

    What I have tried:

    Private _parent As frmMainAlt
    Private _Me As frmOpenAdjustmentsAlt
    Private _crewMgt As frmCrewManagement

    _parent = parent


    RemoveHandler _parent.RefreshClick, AddressOf _crewMgt.RefreshData

    AddHandler _parent.RefreshClick, AddressOf refreshgrid

    here requirement is that by default in all cases Refreshclick of main form should be handled by Refreshadata of frmcrew_managment but when frmOpenAdjustment is loaded from menu option Refreshclick of main form should be handled by RefreshGriddata of frmOpenAdjustment 


    Thursday, April 5, 2018 9:27 PM

All replies

  • The base rule of thumb is to keep track of handlers, subscribe, when done, unsubscribe.

    I may be wrong but someone here (possibly Reed) may have written this.

    Public Class Form1
    
        Dim object1 As New Button
    
        Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
            AddHandler object1.Click, AddressOf Object1_Click
        End Sub
    
        Private Sub Object1_Click(ByVal sender As Object, ByVal e As System.EventArgs)
    
        End Sub
    
        Private Sub Button1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
            'NB: EventName is case sensitive
            If HandlerContains(object1, "Object1_Click", "Click") Then
                MsgBox("Found Handler")
            End If
        End Sub
    
        Private Function HandlerContains(ByVal Obj As Control, ByVal TheMethod As String, ByVal EventName As String) As Boolean
            Dim T = Obj.GetType.GetProperty("Events", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)
            Dim Key = GetType(Control).GetField("Event" & EventName, Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Static).GetValue(Obj)
            Dim EventHandlerList = T.GetValue(Obj, New Object() {})
            Dim MethodFind = EventHandlerList.GetType.GetMethod("Find", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)
            Dim ListEntry = MethodFind.Invoke(EventHandlerList, New Object() {Key})
            Dim Del = ListEntry.GetType.GetField("handler", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)
            Dim MultiCastDelegate = Del.GetValue(ListEntry)
            Dim MethodGIL = MultiCastDelegate.GetType.GetMethod("GetInvocationList")
            Dim EvocationList() As [Delegate] = CType(MethodGIL.Invoke(MultiCastDelegate, Nothing), [Delegate]())
            For Each Target As [Delegate] In EvocationList
                If Target.Method.Name = TheMethod Then
                    Return True
                End If
            Next
            Return False
        End Function
    
    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, April 5, 2018 9:53 PM
  • Now in the main form one of Menu options is OpenAdjustment (frmOpenAdjustment ) . So onclick of OpenAdjustment option, in it's form load (for frmOpenAdjustment ) I need to attach RefreshGriddata Method (of frmOpenAdjustment) to RefreshClick event of Main Form sothat when user clicks Refresh on main screen RefreshGriddata Method of frmOpenAdjustment is called.

    That is not the correct solution to that problem.  The correct solution is to insert code in the main form handler for the RefreshClick button click event to determine whether the code that executes in that event handler is the code that updates the main form or the code that updates the OpenAdjustment form.  Since most of the update task is the same for both forms, the changes needed to update the other form will be slight.

    That requires that when you open the OpenAdjustment form you create a new instance of that form (you do not rely on the default instance) and that you save that instance to a variable created for the purpose.  Then, in the RefreshClick button click event handler code you test that variable.  If it's Nothing then you update the main form,  If it's not Nothing then you update the form that the variable refers to.

    You will also need to set the variable back to Nothing when you close the OpenAdjustment form.  To do that you will need to ensure that the variable that stores the OpenAdjustment form instance in the main form is public or friend, and that the OpenAdjustment form obtains a reference to the form that opened it, so it can update that variable to Nothing as it closes.

    Friday, April 6, 2018 12:17 AM
  • This is a Windows Forms question, right? It does not belong in the C# or VB.Net forum. Please confirm that this is asking about Windows Forms, that is implied but never stated explicitly. I will read the question again if I get a response but if my question is ignored then I will assume that nay other help I might offer will also be ignored.


    Sam Hobbs
    SimpleSamples.Info

    Friday, April 6, 2018 2:59 AM
  • I may be wrong but someone here (possibly Reed) may have written this.

    Doesn't look familiar... I don't think it was mine as it doesn't look like any of my coding styles (unless its just so old that I can't remember or recognize it).

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Friday, April 6, 2018 4:37 PM
  • This is a Windows Forms question, right? It does not belong in the C# or VB.Net forum. Please confirm that this is asking about Windows Forms, that is implied but never stated explicitly. I will read the question again if I get a response but if my question is ignored then I will assume that nay other help I might offer will also be ignored.


    Sam Hobbs
    SimpleSamples.Info

    Sam,

    This thread was moved here by a moderator (Karen); I don't know if you can see that or not at the bottom of the first post, but certainly you can see that a moderator has replied to the thread and so is aware of it.

    I would agree with Karen that the thread belongs here because add/remove handler is a VB language feature, not a Windows Forms feature (managing event handlers would be similar in a console application for example).

    Also, as Acamar has pointed out, this is probably more of a design issue than anything.

    In the future, please refrain from redirecting the OP (or informing them that their thread is on the wrong forum) when a moderator has already moved the thread and/or contributed to the conversation.  If you still believe a thread is in the wrong forum (not all moderators move threads like they should), or no moderator has responded, then please use the "report as abuse - off topic" option to mark the thread and bring it to another moderator's attention.  It can then be moved to the correct forum if applicable and avoid duplications.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Friday, April 6, 2018 4:55 PM
  • Hi Reed Kimble thanks !!  for your response...

    Since this application is already running in production for last 8 years,  So  to avoid any risk I don't want to make any design changes now. Any other suggestion/ solution (which do not involve design changes) is highly appreciated.

    What is the best way to get list of all attached (event) handler to an event of a form?

    and How can we remove all  attached (event) handler to an event of a form?

    Friday, April 6, 2018 5:23 PM
  • I may be wrong but someone here (possibly Reed) may have written this.

    Doesn't look familiar... I don't think it was mine as it doesn't look like any of my coding styles (unless its just so old that I can't remember or recognize it).

    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Okay, I stand corrected :-)

    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

    Friday, April 6, 2018 5:26 PM
  • Please see the example posted by Karen.  This contains code to find an event handler if it exists.

    Note that the design changes need to correct the issue as Acarmar suggests are likely no greater a change than modifying the event handlers will be (unless the program is using default forms, which would be unfortunate).  I would not dismiss his suggestion out of hand.


    Reed Kimble - "When you do things right, people won't be sure you've done anything at all"

    Friday, April 6, 2018 5:30 PM
  • If RefreshClick is a custom event declared with ‘Public Custom Event …’ and relies on an underlying delegate field, then you can clear the list by assigning Nothing to the delegate field.

    Show some details about your event declaration.

    Friday, April 6, 2018 5:46 PM
  • Public Class frmMainAlt

        Public Event RefreshClick()

    .

    .

     .other mthods..

     in main form (frmMainAlt) only event is declared and no implementation of RefreshClick() event . Event handler(RefreshData) is added in frmCrewManagement

     Public Sub New(parentform As Form)
            InitializeComponent()
            _parentform = parentform
            AddHandler DirectCast(_parentform, frmMainAlt).RefreshClick, AddressOf RefreshData

    ...

     

    and in similar way in frmOpenAdjustmentsAlt as well

      Public Sub New(ByVal parent As ContainerControl)
            InitializeComponent()
             _parent = parent
            AddHandler _parent.RefreshClick, AddressOf refreshgrid

    So I tried approach mentioned above by karen but is result in exception at below line

      Dim Del = ListEntry.GetType.GetField("handler", Reflection.BindingFlags.NonPublic Or Reflection.BindingFlags.Instance)

        because its expecting one handler which in my case is not defined (in main form (frmMainAlt) only event is declared and no implementation of RefreshClick() event )

     

    Friday, April 6, 2018 6:06 PM
  • If you still believe that clearing the event is the appropriate approach, then check Custom Events, which can be used in modern VB:

     

    Public Class frmMainAlt
    
       Private RefreshClickDelegate As EventHandler
    
       Public Custom Event RefreshClick As EventHandler
          AddHandler(value As EventHandler)
             RefreshClickDelegate = CType([Delegate].Combine(RefreshClickDelegate, value), EventHandler)
          End AddHandler
    
          RemoveHandler(value As EventHandler)
             RefreshClickDelegate = CType([Delegate].Remove(RefreshClickDelegate, value), EventHandler)
          End RemoveHandler
    
          RaiseEvent(sender As Object, e As EventArgs)
             RefreshClickDelegate?.Invoke(sender, e)
          End RaiseEvent
       End Event
    
       . . .

    Then add a public function that clears the handlers:

       Public Sub ClearRefreshClick()
          RefreshClickDelegate = Nothing
       End Sub
     



    • Edited by Viorel_MVP Friday, April 6, 2018 6:38 PM
    • Proposed as answer by Stanly Fan Monday, April 9, 2018 6:23 AM
    Friday, April 6, 2018 6:36 PM