您可以轻松地从集合中的类中引发事件,问题是另一个类没有直接的方法来接收来自同一类的多个事件的事件。
您clsPeople
通常接收事件的方式是这样的:
Dim WithEvents aPerson As clsPerson
Public Sub AddPerson(p As clsPerson)
Set aPerson = p ' this automagically registers p to the aPerson event-handler `
End Sub
Public Sub aPerson_SelectedChange
...
End Sub
因此,将对象设置到任何声明的变量WithEvents
中都会自动注册它,以便该变量的事件处理程序接收它的事件。 不幸的是,一个变量一次只能保存一个对象,因此该变量中的任何先前对象也会自动取消注册。
对此的解决方案(同时仍然避免 COM 中的引用循环问题)是为此使用共享委托。
所以你做了一个这样的类:
<<Class clsPersonsDelegate>>
Public Event SelectedChange
Public Sub Raise_SelectedChange
RaiseEvent SelectedChange
End Sub
现在不是引发他们自己的事件或都调用他们的父事件(进行引用循环),而是让他们都SelectedChange
在委托类的单个实例中调用子。你让父/集合类从这个单一的委托对象接收事件。
细节
对于各种情况,有很多技术细节需要解决,具体取决于您如何使用这种方法,但以下是主要的:
不要让子对象(Person)创建委托。让父/容器对象 (People) 创建单个委托,然后在将其添加到集合时将其传递给每个子。然后,孩子会将其分配给本地对象变量,然后可以稍后调用其方法。
通常,您会想知道集合中的哪个成员引发了事件,因此clsPerson
向委托 Sub 和事件添加类型参数。那么当调用委托Sub时,Person对象应该通过这个参数传递一个对自身的引用,委托也应该通过Event传递给父对象。只要委托不保存它的本地副本,这不会导致引用周期问题。
如果您希望父级接收更多事件,只需将更多 Subs 和更多匹配事件添加到同一个委托类。
示例实现
响应对“让父/容器对象(人)创建单个委托,然后将其传递给每个孩子,因为它们被添加到集合中的更具体示例的请求。 ”
这是我们的委托类。请注意,我已将调用子对象的参数添加到方法和事件中。
<<Class clsPersonsDelegate>>
Public Event SelectedChange(obj As clsPerson)
Public Sub RaiseSelectedChange(obj As clsPerson)
RaiseEvent SelectedChange(obj)
End Sub
这是我们的子类(Person)。我已经用一个公共变量替换了原始事件来保存委托。我还将 RaiseEvent 替换为对该事件的委托方法的调用,将对象指针传递给自身。
<<Class clsPerson>>
Private pSelected as boolean
'Public Event SelectedChange()'
' Instead of Raising an Event, we will use a delegate'
Public colDelegate As clsPersonsDelegate
Public Property Let Selected (newVal as boolean)
pSelected = newVal
'RaiseEvent SelectedChange'
colDelegate.RaiseSelectedChange(Me)
End Property
Public Property Get Selected as boolean
Selected = pSelected
End Property
这是我们的父/自定义集合类(人员)。我已将委托添加为对象 vairable WithEvents(它应该与集合同时创建)。我还添加了一个示例 Add 方法,该方法显示在将子对象委托属性添加(或创建)到集合时设置它。Set item.colDelegate = Nothing
当它从集合中删除时,您还应该有一个对应的。
<<Class clsPeople>>
Private colPeople as Collection
Private WithEvents colDelegate as clsPersonsDelegate
Private Sub Class_Initialize()
Set colPeople = New Collection
Set colDelegate = New clsPersonsDelegate
End Sub
' Item set as default interface by editing vba source code files'
Public Property Get Item(Index As Variant) As clsPerson
Set Item = colPeople.Item(Index)
End Property
' New Enum set to -4 to enable for ... each to work'
Public Property Get NewEnum() As IUnknown
Set NewEnum = colPeople.[_NewEnum]
End Property
' If selected changes on any person in our collection, do something'
Public Sub colDelegate_SelectedChange(objPerson as clsPerson)
' Do Stuff with objPerson, (just don't make a permanent local copy)'
End Sub
' Add an item to our collection '
Public Sub Add(ExistingItem As clsPerson)
Set ExistingItem.colDelegate = colDelegate
colPeople.Add ExistingItem
' ... '
End Sub