3

I'm new to VB.Net (I'm from a foxpro background) and have had my head in a book for the last two weeks trying to get started with some of the basics.

I'm trying to master class inheritance and have what I hope is not too much of a challenging question.

I've created a class and compiled it as a DLL. It simply allows me to place a button on a form. I just want to capture the Click event - which I've managed to do but would like to override the inherited code rather than having both fire which seems to be happening at the moment.

I realise I could just double click the control and enter code directly into the MyButton1 click event but wanted to trap this programmatically instead via the handler.

I thought this would just be a case of using the overridable / overrides options.

Here's the code in my class:

Imports System.Windows.Forms
Imports System.Drawing

Public Class MyButton

    Inherits Windows.Forms.Button

    Sub New()

    End Sub

    Protected Overridable Sub MyButton_Click(sender As Object, e As System.EventArgs) Handles Me.Click

        MsgBox("Base Click")

    End Sub

End Class

Then I place the button on my form and name it MyButton1 and in the load event:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load

    AddHandler MyButton1.Click, AddressOf Button_Click

End Sub

Private Sub Button_Click()
    MsgBox("Actual Click")
End Sub

Problem is, both events fire and I want the option to override / turn off the base event.

I thought I could just add the 'overrides' keyword to the Button_Click routine i.e.:

Private Sub Overrides Button_Click()

but I get an error message Sub Button_Click() cannot be declared 'overrides' because it does not override a sub in a base class

So to clarify - at the moment my code fires both events so I get two messages. I want to be able to turn off / supress the base class event.

Any help would be much appreciated.

1
  • 2
    You must override OnClick instead. In the MyButton class, not the form. If you don't call MyBase.OnClick then the Click event will not be raised. Commented Dec 28, 2014 at 14:00

2 Answers 2

5

I thought this would just be a case of using the overridable / overrides options.

The fundamental problem here is that you're trying to push a square peg into a round hole.

To override something, you need to have inheritance involved. The derived class is overriding something that was inherited from the base class. For instance, if you inherited from your MyButton class to create a new type of Button called MyButtonDerived, then you could do it as expected:

Public Class MyButton
    Inherits Windows.Forms.Button

    Protected Overridable Sub MyButton_Click(sender As Object, e As System.EventArgs) Handles Me.Click
        MsgBox("Base Click")
    End Sub

End Class

Public Class MyButtonDerived
    Inherits MyButton

    Protected Overrides Sub MyButton_Click(sender As Object, e As EventArgs)
        ' We don't call the base method...
        ' MyBase.MyButton_Click(sender, e) 

        ' ... and instead do something else:
        MsgBox("Derived Click")
    End Sub

End Class

In contrast, when you've placed MyButton onto the Form as in your original problem description, no inheritance has taken place. Instead what you've setup is "object composition"; the form contains an instance of the button (not derived from it). While it may be possible to change what happens when the button is clicked from the form itself, this is not a case that can be solved with OOP, inheritance and overriding.

If MyButton was not designed in such a way that allows the end user to suppress its base functionality, then your options are limited in how you can use it. Here is an example of what it might look like if MyButton was designed to allow the end user to suppress its base click functionality:

Public Class Form1

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        MyButton1.SuppressDefaultClick = True
    End Sub

    Private Sub MyButton1_Click(sender As Object, e As EventArgs) Handles MyButton1.Click
        MsgBox("Form Click Code")
    End Sub

End Class

Public Class MyButton
    Inherits Windows.Forms.Button

    Private _suppress As Boolean = False
    Public Property SuppressDefaultClick As Boolean
        Get
            Return _suppress
        End Get
        Set(value As Boolean)
            _suppress = value
        End Set
    End Property

    Protected Overridable Sub MyButton_Click(sender As Object, e As System.EventArgs) Handles Me.Click
        If Not SuppressDefaultClick Then
            MsgBox("Base Click")
        End If
    End Sub

End Class

If MyButton didn't include a way to suppress its built-in click handler like above then you'd have to resort to other means to solve your problem. In that case you'd have to prevent the button from ever receiving the message that the left mouse button has been clicked at all, and instead implement your own routine. This approach would be a considered a hack, since you are working around the limitations of something and not using it in the way it was originally intended. Here's one way the hack could be implemented:

Public Class Form1

    Private WithEvents TMBC As TrapMyButtonClick

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        TMBC = New TrapMyButtonClick(Me.MyButton1)
    End Sub

    Private Sub TMBC_Click(sender As MyButton) Handles TMBC.Click
        MsgBox("Form Click Code")
    End Sub

    Private Class TrapMyButtonClick
        Inherits NativeWindow

        Private _mb As MyButton

        Private Const WM_LBUTTONDOWN As Integer = &H201

        Public Event Click(ByVal sender As MyButton)

        Public Sub New(ByVal mb As MyButton)
            If Not IsNothing(mb) AndAlso mb.IsHandleCreated Then
                _mb = mb
                Me.AssignHandle(mb.Handle)
            End If
        End Sub

        Protected Overrides Sub WndProc(ByRef m As Message)
            Select Case m.Msg
                Case WM_LBUTTONDOWN
                    RaiseEvent Click(Me._mb) ' raise our custom even that the form has subscribed to
                    Exit Sub ' Suppress default behavior

            End Select
            MyBase.WndProc(m)
        End Sub

    End Class

End Class

Public Class MyButton
    Inherits Windows.Forms.Button

    Protected Overridable Sub MyButton_Click(sender As Object, e As System.EventArgs) Handles Me.Click
        MsgBox("Base Click")
    End Sub

End Class
Sign up to request clarification or add additional context in comments.

1 Comment

Much appreciated...all making sense
1

You are getting 2 messages because you have set 2 different event handlers for the Click event:

  1. The MyButton_Click method defined in your MyButton class.
  2. The Button_Click method set in your AddHandler call on the form.

As noted in a comment above, you need to override the Button.OnClick method in your MyButton class instead of creating a new method:

Imports System.Windows.Forms
Imports System.Drawing

Public Class MyButton
    Inherits Windows.Forms.Button

    Sub New()
    End Sub

    ' Override the OnClick event defined in "Button" class.
    Protected Overrides Sub OnClick(e As System.EventArgs)
        ' Call the Click event from "Button" class.
        MyBase.OnClick(e)

        ' Some custom events.
        MsgBox("MyButton Click")
    End Sub

End Class

It might be a good exercise to set breakpoints in the Button_Click and MyButton.OnClick methods so you can see exactly how the stack is created.

2 Comments

Still a little confused as I want to 'optionally' stop the base click from firing....i.e. I may want to execute the base click AND my own click or simply just my own. Can this be done?
@AndyTrezise - This could be done but your MyButton instance would have to evaluate these conditions in the OnClick method (which means you may have to provide it with additional information when creating the object). The other answer provided gives a good example of this.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.