gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-04 03:38:18 25 4
gpt4 key购买 nike

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

显然,您可以告诉子类对父类的引用,然后在子类中调用父类中的公共(public)方法,但这会导致循环引用,据我所知,这会使垃圾收集器永远不会摆脱任何一个对象。

细节:
我有两个类,一个是名为 clsPerson 的人,第二个是一个名为 clsPeople 的自定义集合类。 clsPerson 有一个名为 Selected 的公共(public) bool 属性。如果 selected 被更改,我将调用一个事件 SelectedChange。那时,我需要在 clsPeople 中做一些事情。如何在自定义集合类 clsPeople 中捕获事件?可以从 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

最佳答案

您可以轻松地从集合中的一个类中引发事件,问题是另一个类没有直接的方法来接收来自同一类的多个事件的事件。
您的 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 中的引用循环问题)是为此使用共享委托(delegate)。
所以你做了一个这样的类:
<<Class clsPersonsDelegate>>

Public Event SelectedChange

Public Sub Raise_SelectedChange
RaiseEvent SelectedChange
End Sub
现在不是引发他们自己的事件或都调用他们的父事件(创建一个引用循环),而是让他们都调用 SelectedChange sub 在委托(delegate)类的单个实例中。你让父/集合类从这个单一的委托(delegate)对象接收事件。
详情
对于各种情况,有很多技术细节需要解决,具体取决于您如何使用这种方法,但以下是主要的:
  • 不要让子对象(Person)创建委托(delegate)。让父/容器对象 (People) 创建单个委托(delegate),然后在将其添加到集合时将其传递给每个子。然后, child 会将其分配给本地对象变量,然后可以稍后调用其方法。
  • 通常,您会想知道您的集合中的哪个成员引发了事件,因此添加类型为 clsPerson 的参数到委托(delegate)子和事件。那么当调用委托(delegate)Sub时,Person对象应该通过这个参数传递一个对自身的引用,委托(delegate)也应该通过Event传递给父对象。只要委托(delegate)不保存它的本地副本,这不会导致引用周期问题。
  • 如果您希望父级接收更多事件,只需将更多 Subs 和更多匹配事件添加到同一个委托(delegate)类。

  • 示例实现
    响应对“让父/容器对象(人员)创建单个委托(delegate),然后在每个 child 添加到集合时将其传递给每个 child ”的更具体示例的请求。
    这是我们的委托(delegate)类。请注意,我已将调用子对象的参数添加到方法和事件中。
    <<Class clsPersonsDelegate>>

    Public Event SelectedChange(obj As clsPerson)

    Public Sub RaiseSelectedChange(obj As clsPerson)
    RaiseEvent SelectedChange(obj)
    End Sub
    这是我们的子类(Person)。我已经用一个公共(public)变量替换了原始事件来保存委托(delegate)。我还将 RaiseEvent 替换为对该事件的委托(delegate)方法的调用,将对象指针传递给自身。
    <<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
    这是我们的父/自定义集合类(人员)。我已将委托(delegate)添加为对象 vairable WithEvents(它应该与集契约(Contract)时创建)。我还添加了一个示例 Add 方法,该方法显示在将子对象委托(delegate)属性添加(或创建)到集合时设置它。您还应该有一个相应的 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

    关于vba - 从自定义集合类中的对象引发事件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19280524/

    25 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com