Vba 从自定义集合类中的对象引发事件

Vba 从自定义集合类中的对象引发事件,vba,events,Vba,Events,如果一个对象包含在一个集合中,该对象是否仍能向父类引发事件 很明显,您可以告诉子类一个对父类的引用,然后在子类内调用父类内的公共方法,但是这将导致循环引用,据我所知,这将使垃圾回收器无法摆脱这两个对象 详情: 我有两个类,一个是名为clsPerson的人,另一个是名为clsPeople的自定义集合类。clsPerson有一个名为Selected的公共布尔属性。如果selected被更改,我将调用事件SelectedChange。在这一点上,我需要在clsPeople做些事情。如何在自定义集合类c

如果一个对象包含在一个集合中,该对象是否仍能向父类引发事件

很明显,您可以告诉子类一个对父类的引用,然后在子类内调用父类内的公共方法,但是这将导致循环引用,据我所知,这将使垃圾回收器无法摆脱这两个对象

详情: 我有两个类,一个是名为clsPerson的人,另一个是名为clsPeople的自定义集合类。clsPerson有一个名为Selected的公共布尔属性。如果selected被更改,我将调用事件SelectedChange。在这一点上,我需要在clsPeople做些事情。如何在自定义集合类clsPeople中捕获事件?person类可以在People范围之外进行更改,否则我将考虑另一种解决方案

<<Class clsPerson>>
Private pSelected as boolean

Public Event SelectedChange()

Public Property Let Selected (newVal as boolean)
  pSelected = newVal
  RaiseEvent SelectedChange
End Property

Public Property Get Selected as boolean
  Selected = pSelected
End Property

<<Class clsPeople>>
Private colPeople as Collection

' 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 a person, do something
Public Sub ???_SelectedChange
  ' Do Stuff
End Sub

选为布尔值的私有PSP
公共事件SelectedChange()
选定的公共属性(newVal为布尔值)
pSelected=newVal
RaiseEvent Selected更改
端属性
公共属性被选为布尔值
选中=pSelected
端属性
私人收藏
'通过编辑vba源代码文件将项设置为默认界面
公共属性获取项(索引作为变量)作为clsPerson
Set Item=colPeople.Item(索引)
端属性
'将新枚举设置为-4以启用。。。各就各位
公共属性获取NewEnum()作为IUnknown
Set NewEnum=colPeople。[[u NewEnum]
端属性
'如果选定的更改发生在某个人身上,请执行某些操作
公共子系统???\u选择更改
“做事
端接头

您可以轻松地从集合中的类引发事件,问题是另一个类无法直接从同一个类的多个类接收事件

您的
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
<<Class clsPersonsDelegate>>

Public Event SelectedChange

Public Sub Raise_SelectedChange
    RaiseEvent SelectedChange
End Sub
因此,将对象设置到任何声明为
with events
的变量中,会自动注册该对象,以便该变量的事件处理程序接收该对象的事件。不幸的是,一个变量一次只能保存一个对象,因此该变量中以前的任何对象也会自动取消注册

对此的解决方案(同时仍然避免COM中引用周期的问题)是为此使用共享委托

因此,您可以创建这样一个类:

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
<<Class clsPersonsDelegate>>

Public Event SelectedChange

Public Sub Raise_SelectedChange
    RaiseEvent SelectedChange
End Sub
这是我们的儿童班(人)。我已经用一个公共变量替换了原始事件来保存委托。我还将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

这段代码对我非常有帮助。它帮助我在VBA中同时使用接口和事件。谢谢你的发帖!在将其付诸实践后,只需对其进行几处小的更正:1)可以从
clspersonsdegate
类中的方法名称中删除文本
Raise\uu
。2) 需要更改
clsPeople
上的
colDelegate\u SelectedChange
方法,以接受
clsPerson
类型的参数。另外,对于尝试此代码的其他人,
clsPeople
将需要一个初始化方法来
Set colPeople=New Collection
Set colDelegate=New clspersonsdegate
@barrettnashille Thx!是的,
Raise\uuu
前缀不是必须的,我只是把它当作一种风格来使用:我喜欢保持名字的清晰,这样我就总能知道引用的是哪个。巴雷特纳什维尔的评论也是如此,对我也非常有帮助。谢谢,非常感谢!