【问题标题】:VB.Net Inheritance OverrideVB.Net 继承覆盖
【发布时间】:2014-12-28 13:50:20
【问题描述】:

我是 VB.Net 的新手(我来自 foxpro 背景),并且在过去的两周里一直在努力学习一些基础知识。

我正在尝试掌握类继承,并希望得到一个不太具有挑战性的问题。

我创建了一个类并将其编译为 DLL。它只是允许我在表单上放置一个按钮。我只想捕获 Click 事件 - 我已经设法做到了,但想覆盖继承的代码,而不是同时发生目前似乎正在发生的两种火灾。

我意识到我可以双击控件并直接在 MyButton1 点击事件中输入代码,但我想通过处理程序以编程方式捕获它。

我认为这只是使用可覆盖/覆盖选项的情况。

这是我课堂上的代码:

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

然后我将按钮放在我的表单上并将其命名为 MyButton1 并在加载事件中:

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

问题是,两个事件都会触发,我想要覆盖/关闭基本事件的选项。

我想我可以将“覆盖”关键字添加到 Button_Click 例程,即:

Private Sub Overrides Button_Click()

但我收到一条错误消息无法将子 Button_Click() 声明为“覆盖”,因为它不会覆盖基类中的子项

所以澄清一下 - 目前我的代码触发了两个事件,所以我收到了两条消息。我希望能够关闭/抑制基类事件。

任何帮助将不胜感激。

【问题讨论】:

  • 您必须改写 OnClick。在 MyButton 类中,而不是表单中。如果您不调用 MyBase.OnClick,则不会引发 Click 事件。

标签: vb.net


【解决方案1】:

我认为这只是使用可覆盖 / 覆盖选项。

这里的根本问题是您试图将方形钉子推入圆孔中。

要覆盖某些内容,您需要涉及继承。派生类覆盖了从基类继承的东西。例如,如果您从 MyButton 类继承来创建一种名为 MyButtonDerived 的新型 Button,那么您可以按预期进行:

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

相反,当您按照最初的问题描述将 MyButton 放置到 Form 上时,并没有发生继承。相反,您设置的是“object composition”;表单包含按钮的一个实例(不是从它派生的)。虽然可以更改从表单本身单击按钮时发生的情况,但这不是可以通过 OOP、继承和覆盖来解决的情况。

如果 MyButton 的设计不是允许最终用户抑制其基本功能,那么您的选择将受限于如何使用它。如果 MyButton 被设计为允许最终用户抑制其基本点击功能,下面是一个示例:

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

如果 MyButton 没有像上面那样包含抑制其内置点击处理程序的方法,那么您将不得不求助于其他方法来解决您的问题。在这种情况下,您必须阻止按钮接收到鼠标左键已被单击的消息,而是实现您自己的例程。这种方法将被视为一种 hack,因为您正在围绕某些东西的限制工作,而不是按照最初预期的方式使用它。以下是可以实施 hack 的一种方式:

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

【讨论】:

  • 非常感谢......一切都有意义
【解决方案2】:

您收到 2 条消息,因为您为 Click 事件设置了 2 个不同的事件处理程序:

  1. MyButton_Click 方法在您的 MyButton 类中定义。
  2. 在表单上的AddHandler 调用中设置的Button_Click 方法。

如上面评论中所述,您需要在 MyButton 类中重写 Button.OnClick 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

Button_ClickMyButton.OnClick 方法中设置断点可能是一个很好的练习,这样您就可以准确地看到堆栈是如何创建的。

【讨论】:

  • 感谢 cmets。
  • 仍然有点困惑,因为我想“选择性地”阻止基本点击触发......即我可能想执行基本点击和我自己的点击,或者只是我自己的点击。这个可以吗?
  • @AndyTrezise - 可以这样做,但您的 MyButton 实例必须在 OnClick 方法中评估这些条件(这意味着您可能必须在创建对象时向其提供其他信息) .提供的另一个答案就是一个很好的例子。
猜你喜欢
  • 1970-01-01
  • 2019-06-29
  • 1970-01-01
  • 1970-01-01
  • 2013-12-10
  • 2017-09-21
  • 2012-11-20
  • 2017-09-30
相关资源
最近更新 更多