VB.Net 如何将处理程序附加到泛型 class
VB.Net How to attach a handler to a generic class
我有一个 class 'oBnd' 定义为可以指定为类型 clsBound 或 clsClaim 的对象。
Claim 和 bound 从外部看是相同的,相同的方法等。
我使用 'CallByName' 调用各种属性
即Dim Current As String = CallByName(oBnd, PropName, CallType.Get)
当 class 中的 属性 发生变化时,class 引发 DirtyStatus 事件。
我在附加到此事件时遇到问题。
如果我尝试
AddHandler oBnd.DirtyStatus, AddressOf oBnd_DirtyStatus
我收到错误 "DirtyStatus is not an event of 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
如何将句柄附加到此事件?
这里是您既可以使事件正常工作又可以避免使用反射来访问属性的方法。即使给定 the public methods are similar but the data being carried is very different
,仍然可以使用 OOP/Inheritance。
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
你必须做一些基本的数据分析来弄清楚哪些属性和方法可以在基础 class 中实现(与上面的 Name
一样),哪些在继承 classes。通常至少有一些可以在基础 class 中完成。
您派生的 classes 可以完全 不同的方式实现方法并从任何地方加载数据:
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
的情况下实现它们,订阅事件而不必对 get/set 属性使用反射:
' '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
。由于事件是基础class的一部分,所以语法没有问题。表单级处理程序:
' 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/when 有类型特定的 properties/methods 可以访问,转换它(根据你所说的,现在不可能有任何这些):
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
并不是为了专注于继承,尽管它的基础知识在那个基础 class 中。它是实现 DataChanged/DirtyStatus 事件和检测的一种更系统的方法。
我有一个 class 'oBnd' 定义为可以指定为类型 clsBound 或 clsClaim 的对象。 Claim 和 bound 从外部看是相同的,相同的方法等。
我使用 'CallByName' 调用各种属性
即Dim Current As String = CallByName(oBnd, PropName, CallType.Get)
当 class 中的 属性 发生变化时,class 引发 DirtyStatus 事件。
我在附加到此事件时遇到问题。
如果我尝试
AddHandler oBnd.DirtyStatus, AddressOf oBnd_DirtyStatus
我收到错误 "DirtyStatus is not an event of 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
如何将句柄附加到此事件?
这里是您既可以使事件正常工作又可以避免使用反射来访问属性的方法。即使给定 the public methods are similar but the data being carried is very different
,仍然可以使用 OOP/Inheritance。
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
你必须做一些基本的数据分析来弄清楚哪些属性和方法可以在基础 class 中实现(与上面的 Name
一样),哪些在继承 classes。通常至少有一些可以在基础 class 中完成。
您派生的 classes 可以完全 不同的方式实现方法并从任何地方加载数据:
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
的情况下实现它们,订阅事件而不必对 get/set 属性使用反射:
' '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
。由于事件是基础class的一部分,所以语法没有问题。表单级处理程序:
' 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/when 有类型特定的 properties/methods 可以访问,转换它(根据你所说的,现在不可能有任何这些):
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
并不是为了专注于继承,尽管它的基础知识在那个基础 class 中。它是实现 DataChanged/DirtyStatus 事件和检测的一种更系统的方法。