Regular Jo
Regular Jo

Reputation: 5510

Getting Event Handler from Instance of Class

I'm just getting started with custom classes so I wrote a button strip. It inherits a panel and populates it with buttons from strings passed to my .Add().

ButtonStrip1.Add("Button","Texts","Go Here")

I'd like for it to be able to naturally grab ButtonStrip1.Click's handler and pass it on to child buttons and delete it from ButtonStrip1.

I haven't been able to figure that out, so I've been doing

Public Class ButtonStrip
    Inherits Panel
    Public Property Innermargin As Integer = 5
    Dim Offset As Integer = Innermargin
    Dim Buttons = New List(Of ButtonStrip_Button)
    Dim StoredFN As EventHandler

    Public Sub New()
    End Sub

    Function Add(fn As EventHandler, ParamArray ByVal Values As String())
        StoredFN = fn
        For Each V In Values
            Dim B As New ButtonStrip_Button
            Buttons.Add(B)
            Me.Controls.Add(B)
            B.Text = V
            B.Left = Offset + Innermargin
            B.Top = Innermargin

            Offset = B.Left + B.Width
            AddHandler B.Click, fn
        Next
        RemoveHandler Me.Click, fn
        Me.Width = Offset + Innermargin
        Me.Height = Buttons(0).height + Innermargin * 2
    End Function

    Function Add(ParamArray ByVal Values As String())
        If StoredFN Is Nothing Then
            Throw New Exception("First Add() must supply a function")
        End If
        Me.Add(StoredFN, Values)
    End Function
End Class

Public Class ButtonStrip_Button
    Inherits System.Windows.Forms.Button
    Public Sub New()
        AutoSize = True
        AutoSizeMode = AutoSizeMode.GrowAndShrink
    End Sub
End Class

which is called by

ButtonStrip1.Add(AddressOf ButtonStrip1_Click,"Button","Texts","Go Here")

What I'd basically like to do is (psuedo-code)

Function Add(fn As EventHandler, ParamArray ByVal Values As String())
    If StoredFN is Nothing Then StoredFN = Me.Click
        ...
        AddHandler B.Click, Me.Click
    Next
    RemoveHandler Me.Click, Me.Click
    ...
End Function

I've tried changing a few things and googled a lot. I've also tried using CallByName(Me,"Click",CallType.Method) and with CallType.Get, but the error I get is Expression 'Click' is not a procedure, but occurs as the target of a procedure call. It also returns this exact same message for unhandled events, such as ButtonStrip1 has no MouseDown Event.

I've also tried using MyClass.

Not seen here is an alternative .Add() that add StoredFN to B.click

For instance, this click event works with my code

Private Sub ButtonStrip1_Click(sender As Object, e As EventArgs) Handles ButtonStrip1.Click
    msgbox("You clicked " & sender.text & ".")
End Sub

Upvotes: 0

Views: 362

Answers (1)

jmcilhinney
jmcilhinney

Reputation: 54457

What I was suggesting was something like this:

Public Class ButtonStrip
    Inherits Panel

    Public Event ButtonClick As EventHandler(Of ButtonClickEventArgs)

    Protected Overridable Sub OnButtonClick(e As ButtonClickEventArgs)
        RaiseEvent ButtonClick(Me, e)
    End Sub

    Private Sub Buttons_Click(sender As Object, e As EventArgs)
        OnButtonClick(New ButtonClickEventArgs(DirectCast(sender, Button)))
    End Sub

    Public Sub Add(ParamArray values As String())
        Dim btn As New Button

        AddHandler btn.Click, AddressOf Buttons_Click

        '...
    End Sub

End Class


Public Class ButtonClickEventArgs
    Inherits EventArgs

    Public ReadOnly Property Button As Button

    Public Sub New(button As Button)
        Me.Button = button
    End Sub

End Class

Now there's no need to pass event handlers around. When a Button is clicked, the ButtonStrip handles that event and then raises its own ButtonClick event. Neither the ButtonStrip nor the Buttons have to care about any methods that handle that event as it will be handled the same way any other event is. In a form, you'd then handle the ButtonClick event of the ButtonStrip and get the Button that was clicked from e.Button. You could also add an Index property if you wanted to know the position of the Button rather than the Button itself.

Upvotes: 2

Related Questions