在Visual Basic.net 中,是否可以将事件处理程序添加到 T 列表,以便每当列表更改时,都会调用此事件?
例如,如果我有一个名为 Schedule 的类,并且此 Schedule 有一个 ScheduleItem 列表,那么如何添加在更改此列表时将调用的事件?
有些集合会在列表更改时引发事件(BindingList(of T)
一个),但事件仅适用于列表所在的类/窗体。 对于更广泛的实现,Schedule
类可以引发事件。
-
确保只有
Schedule
对列表进行更改。 也就是说,您的List(Of T)
应该是私有成员。 其他对象应通过它进行更改,以便它完全了解所有更改,从而不会遗漏任何更改。 -
确定什么是变更事件。 添加和删除项目是显而易见的,但根据
ScheduleItem
中的内容,.StartTime
或类似的属性也可能是事件。(这实际上需要对项目类进行INotifyPropertyChanged
) -
对于"添加和删除",每次
Schedule
内部列表中添加或删除项目时,它都会引发事件以通知订阅者。 -
谁将消费(或获取)这些事件? 形式? 其他类结构?
一个简单的方法,一旦在"拥有"列表的类中发生所有更改,就是一个自定义事件:
Public Class Schedule
Private MyList as List (Of ScheduleItem)
Public Event ScheduleChanged(sender As Object, e As EventArgs)
...
Public Sub AddItemToSchedule(....)
' I have no idea what is in a ScheduleItem....
...
MyList.Add(si)
' the point is that if it gets added / not a dupe etc, then:
' tell any subscribers that the sched changed:
RaiseEvent ScheduleChanged(Me, New EventArgs())
End Sub
Public Sub RemoveItem(...)
' do whatever to remove an item
' ...
MyList.Remove(si)
' tell subscribers the sched changed
RaiseEvent ScheduleChanged(Me, New EventArgs())
End Sub
End Class
私人收藏的另一种方法是让Schedule
继承类似的东西 Collection(of T)
. 对于活动的订阅者:
Public Class SomeOtherClass
' These need a reference to the Schedule object
Private WithEvents Sched As Schedule
...
Public Sub New(scObj As Schedule)
Sched = scObj
End Sub
End Class
SomeOtherClass
现在将在左侧 VS 下拉列表中有一个新条目 abs 相关事件:
Private Sub Sched_ScheduleChanged(sender As Object,
e as EventArgs) Handles Sched.ScheduleChanged
' add code here to respond to schedule changes
End Sub
用法:
Dim foo = New SomeOtherClass(SchedObj)
创建 SomeOtherClass
对象的任何内容都会在构造函数中传递Schedule
对象。 如果它是由Schedule
创建的,它将是 Me
.
如果SomeOtherClass
有权访问Schedule
则可以放弃构造函数参数:
Public Sub New()
Sched = mainSchedInstance
End Sub
在所有情况下,Schedule
都需要存在,否则代码将尝试挂接到Nothing
对象上的事件。
笔记
- 在所有事件中传递
Sched
对象(Me
)似乎很奇怪(还有谁会发送ScheduleChanged
事件? 但是 VS 代码分析工具反对Object sender, EventArgs e
以外的事件签名。 - 如果要在事件中传递诸如更改类型之类的信息,请创建一个继承自
EventsArgs
的类,并添加所需的任何属性。 其中之一可能是添加ScheduleItem
还有其他方法可以实现这一点,例如它是Foo.Schedule
的,SomeOtherClass
需要了解该事件。 在这种情况下,Schedule 仍会生成事件,Foo
订阅它,然后引发自己的ScheduleChanged
事件,传递事件参数。 其他演员在Foo
上订阅了该事件。 这被称为"冒泡"事件。
您还可以使用一种方法创建一个小类,并且只执行引发事件。在这种情况下,它将由Schedule
创建,并通过非私有成员提供给任何参与者。 SomeOtherClass
可以从Foo那里获得对Schedule.ScheduleChangeNotifier
的引用。 当列表更改时,Schedule
调用触发事件的方法,并且不涉及 Foo。
此模式通常称为 EventBus,但可以将其视为广播接收器设置:调度使用该类广播通知,其他人使用它将其作为事件接收。 当两个参与者甚至不需要相互了解时,它很有用。
一个例子是Foo.Bar
需要从Fizz.Blorg
知道一些东西:Bar
可以接收这些事件,而不涉及Fizz
或Foo
,除了让总线/通知器对象Bar
。
它比冒泡事件少见,但有时非常有用。 通常,如果看起来这就是答案,我会尝试重新检查设计,看看是否可以简化。
List(Of )
没有提供开箱即用的功能。
您可以创建自己的IList(Of )
实现并实现所需的事件,也可以使用现有集合(如 BindingList(Of )
或 ObservableCollection(Of )
)。