您可以輕鬆地提高從集合類中的一個事件,問題是,有另一個類沒有直接的方法收到大量來自同一類的倍數事件。
您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)創建委託。讓父/容器對象(人員)創建單個委託,然後將其傳遞給每個孩子,因爲他們被添加到集合中。然後,孩子將它分配給一個本地對象變量,然後它可以稍後調用它的方法。
通常情況下,你會想知道其中您的收藏成員提出的事件,所以clsPerson
類型的參數添加到委託Sub和事件。然後,當委託Sub被調用時,Person對象應該通過這個參數傳遞一個對自身的引用,並且委託也應該通過Event將它傳遞給父對象。只要代理不保存本地副本,這不會導致引用循環問題。
如果您有更多需要父級接收的事件,只需將更多的Subs和更多匹配的事件添加到同一個委託類。
響應請求的「具有父/容器對象(人)創建單代表,然後作爲它們被添加到集合它傳遞給每個小孩。」更具體的例子
這是我們的委託類。請注意,我已將調用子對象的參數添加到方法和事件中。
<<Class clsPersonsDelegate>>
Public Event SelectedChange(obj As clsPerson)
Public Sub Raise_SelectedChange(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.SelectedChange(Me)
End Property
Public Property Get Selected as boolean
Selected = pSelected
End Property
這裏是我們的父/定製集合類(People)。我已經將委託添加爲WithEvents(可以與集合同時創建)的對象。我還添加了一個示例Add方法,該方法在添加(或創建)它到集合時顯示設置子對象委託屬性。從集合中刪除時,您還應該有相應的Set item.colDelegate = Nothing
。
<<Class clsPeople>>
Private colPeople as Collection
Private WithEvents colDelegate as clsPersonsDelegate
' 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 out collection, do something'
Public Sub colDelegate_SelectedChange
' Do Stuff'
End Sub
' Add an item to our collection '
Public Sub Add(ExistingItem As clsPerson)
Set ExistingItem.colDelegate = colDelegate
colPeople.Add ExistingItem
' ... '
End Sub
此代碼對我非常有幫助。它幫助我在VBA中一起使用接口和事件。謝謝您的發佈!在將其付諸實踐後,只需對它進行一些小修改:1)可以從'clsPersonsDelegate'類的方法名稱中刪除文本'Raise_'。 2)'clsPeople'上的'colDelegate_SelectedChange'方法將需要改變以接受類型爲'clsPerson'的參數。此外,對於嘗試此代碼的其他人,'clsPeople'需要一個初始化方法來設置colPeople = New Collection和Set colDelegate = New clsPersonsDelegate。 – BarrettNashville
@BarrettNashville Thx!是的,'Raise_'前綴不是必需的,我只是將它用作風格問題:我喜歡將名稱保持不同,以便我始終知道所引用的內容。 – RBarryYoung