VB.Net如何将处理程序附加到泛型类

时间:2015-04-02 12:38:42

标签: vb.net vb.net-2010

我有一个班级' oBnd'定义为Object,可以指定为clsBound或clsClaim类型。 索赔和约束从外部,相同的方法等相同。

我使用' CallByName'来调用各种属性 即Dim Current As String = CallByName(oBnd, PropName, CallType.Get)

当在任一类中更改属性时,该类会引发DirtyStatus事件。

我在附加此事件时遇到问题。

如果我尝试

 AddHandler oBnd.DirtyStatus, AddressOf oBnd_DirtyStatus

我收到错误" DirtyStatus不是Object"我想这是有道理的,因为很明显对象对我的脏状态一无所知。

我尝试使用:

 AddHandler DirectCast(oBnd, clsBound).DirtyStatus, AddressOf oBnd_DirtyStatus

虽然这确实修复了错误,但是在引发DirtyStatus事件时它不会被调用。

oBnd定义为 Private WithEvents oBnd As Object 它是全球形式的

oBnd设置为

        oBnd = New clsBound(mvarBUDConnection)
        AddHandler oBnd.DirtyStatus, AddressOf oBnd_DirtyStatus

        oBnd.Load(CInt(txtTrans.Text))
        BuildPage(oBnd)

或者

        oBnd = New clsClaim(mvarBUDConnection)
        AddHandler oBnd.DirtyStatus, AddressOf oBnd_DirtyStatus

        oBnd.Load(CInt(txtTrans.Text))
        BuildPage(oBnd)

我想附加的oBnd_DirtyStatus子,看起来像这样

Private Sub oBnd_DirtyStatus(IsDirty As Boolean) ' Handles oBnd.DirtyStatus
    Me.Text = "QFix"
    If IsDirty Then
        Me.Text = "QFix - Pending Save"
        btnSave.Enabled = True
    Else
        btnSave.Enabled = False
    End If
End Sub

如何附加此事件的句柄?

1 个答案:

答案 0 :(得分:1)

以下是如何使事件工作并远离使用Reflection访问属性。即使给定the public methods are similar but the data being carried is very different,仍然可以使用OOP /继承。

Public Enum ClaimBoundType
    None            ' error!!!!
    Claim
    Bound
End Enum

Public MustInherit Class ClaimBase
    ' type tracker usually rather handy
    Public Property ItemType As ClaimBoundType

    Public Sub New(t As ClaimBoundType)
        ItemType = t
    End Sub

    ' low rent INotifyPropertyChanged
    Public Event DataChanged(sender As Object, e As EventArgs)

    ' "universal" prop: works the same for all derived types
    Private _name As String = ""
    Public Property Name As String
        Get
            Return _name
        End Get
        Set(value As String)
            If value <> _name Then
                _name = value
                BaseDataChanged(Me)
            End If
        End Set
    End Property

    ' props which must be implemented; 1 or 100 doesnt matter
    MustOverride Property CurrentValue As Integer

    ' methods which must be implemented
    MustOverride Function DoSomething() As Integer

    ' raise the changed event for base or derived classes
    Protected Friend Sub BaseDataChanged(sender As Object)
        RaiseEvent DataChanged(sender, New EventArgs())
    End Sub
End Class

您必须进行一些基本的数据分析,以确定哪些属性和方法可以在基类中实现(与上面的Name一样)以及继承的类中的哪些属性和方法。通常至少有一些可以在基类中完成。

您的派生类可以用完全不同的方式实现方法,并从以下任何地方加载数据:

Public Class Claim
    Inherits ClaimBase   ' the IDE will add all the MustInherits when
                         ' you press enter
    Public Sub New()
        MyBase.New(ClaimBoundType.Claim)
    End Sub

    Public Overrides Function DoSomething() As Integer
        ' what happens here can be completely different 
        ' class to class 
    End Function

    Private _CurValue As Integer = 0
    Public Overrides Property CurrentValue As Integer
        Get
            Return _CurValue
        End Get
        Set(Value As Integer)
            If _CurValue <> Value Then
                _CurValue = Value
                OnDataChanged("CurrentValue")
            End If
        End Set
    End Property

    ' name of prop that changed not actually used here, but
    ' is usually good to know (use custom args or INotifyPropertyChanged)
    Public Sub OnDataChanged(pname As String)
        ' fire shared datachanged event
        MyBase.BaseDataChanged(Me)
    End Sub

End Class

如何使用它们

现在您可以在不诉诸Object的情况下实现它们,订阅事件而不必使用Reflection来获取/设置属性:

 ' 'generic' object variable: DONT/CANT USE [New] w/ClaimBase
 Private myCB As ClaimBase
 ...
' set it as a Claim instance... 
'   This is perfectly legal because Claim is also a ClaimBase Type:
 myCB = New Claim

 ' hook up the event handler
 AddHandler myCB.DataChanged, AddressOf cb_DataChanged

您可以声明您的对象变量为ClaimBase,但您无法创建ClaimBase实例,因为它是abstract / MustInherit。由于事件是基类的一部分,因此语法没有问题。表单级处理程序:

' Use standard (sender, e) signature
' (CA will object to other signatures:)
Private Sub cb_DataChanged(sender As Object, e As EventArgs)
    ' do change stuff here
    ...
End Sub

最重要的是,您可以直接引用属性:

cbObj.Name = "Ziggy"         ' will fire the event from the base class
cbObj.CurrentValue = 42      ' fires event from the Claim class

我添加了ItemType属性,因此您可以在运行时区分它们(即当您将鼠标悬停在ClaimBase对象变量上时)。如果/当有特定类型的属性/方法要访问时,将其强制转换(从你所说的,现在不能出现这些):

If cbObj.ItemType = ClaimBoundType.Claim Then
    CType(cbObj, Claim).ClaimSomething = 5
End If    

同样使用ClaimBase作为Lists的声明类型和方法签名也允许传递任一类型而不是装箱(转换为Object):

Private cbList As New List(Of ClaimBase)
   ...
' just an example of the declaration
Private Sub AddThingToList(cb As ClaimBase)
    cbList.Add(cb)
End Sub

我没有进入INotifyProperty以便专注于继承,尽管它的基础是在该基类中。这是实现DataChanged / DirtyStatus事件和检测的更系统的方法。