Introduction
Because of the limitation of VBA in using events in interfaces I was searching for a kind of workaround.
For sure I also read this which also provides an approach, but I was searching for an easier way.
I ended up with the following solution.
The idea behind
Instead of defining the events directly in an interface - because it is not possible to use them in an implementing class in VBA - I use an additional 'event' class, where all necessary events will be placed in, and which will be injected into the interface implementing classes.
Naming of the event class
I'm aware of that this class is not really used as an interface, but it only should be used with the regarding interface.
So I named it also with an I
prefix.
Another benefit of this is that it will be listed beneath the regarding interface.
Circular references
The worker object is provided with the event on purpose. As long as it is used in the event handler with care, that means, it should not be stored anywhere else, there shouldn't be any risk regarding circular references.
The interfaces
IWorker
Option Explicit
Public Property Set Events(ByRef value As IWorkerEvents)
End Property
Public Sub Work()
End Sub
IWorkerEvents
Option Explicit
Public Event Notify(ByRef worker As IWorker, message As String)
Public Sub Notify(ByRef worker As IWorker, message As String)
RaiseEvent Notify(worker, message)
End Sub
The implementations
Worker1
Option Explicit
Implements IWorker
Private Type TWorker
Events As IWorkerEvents
End Type
Private this As TWorker
Private Property Set IWorker_Events(RHS As IWorkerEvents)
Set this.Events = RHS
End Property
Private Sub IWorker_Work()
Debug.Print "Worker 1 works hard."
Notify "is working..."
End Sub
Sub Notify(ByVal message As String)
If Not this.Events Is Nothing Then
this.Events.Notify Me, message
End If
End Sub
Worker2
Option Explicit
Implements IWorker
Private Type TWorker
Events As IWorkerEvents
End Type
Private this As TWorker
Private Property Set IWorker_Events(RHS As IWorkerEvents)
Set this.Events = RHS
End Property
Private Sub IWorker_Work()
Debug.Print "Worker 2 works hard."
Notify "is working..."
End Sub
Sub Notify(ByVal message As String)
If Not this.Events Is Nothing Then
this.Events.Notify Me, message
End If
End Sub
Building it together
TestClass
Option Explicit
Dim WithEvents workerEvents As IWorkerEvents
Sub Test()
Dim worker As IWorker
Set workerEvents = New IWorkerEvents
Set worker = New worker1
Set worker.Events = workerEvents
worker.Work
Set worker = New worker2
Set worker.Events = workerEvents
worker.Work
End Sub
Private Sub workerEvents_Notify(worker As IWorker, message As String)
Debug.Print "TestClass says:", TypeName(worker), message
End Sub
TestModule
Option Explicit
Sub Test()
With New testClass
.Test
End With
End Sub
Output
Worker 1 works hard.
TestClass says: Worker1 is working...
Worker 2 works hard.
TestClass says: Worker2 is working...