You should take note of how classes like the System.Timers.Timer and FileSystemWatcher work. They have a SynchronisingObject property that tells them what thread to raise their events on. You could use .NET Reflector to see exactly how it's implemented but at a guess it would be something like this:
vb Code:
  1. Public Event SomeEvent(ByVal sender As Object, ByVal e As EventArgs)
  2.  
  3. Protected Delegate Sub EventRaiser(ByVal e As EventArgs)
  4.  
  5. Protected Sub OnSomeEvent(ByVal e as EventArgs)
  6.     If Me.SynchronizingObject IsNot Nothing AndAlso _
  7.        Me.SynchronizingObject.InvokeRequired Then
  8.         'Raise the event on the thread that owns the synchronising object.
  9.         Me.SynchronizingObject.Invoke(New EventRaiser(AddressOf OnSomeEvent), e)
  10.     Else
  11.         'Raise the event on the current thread.
  12.         RaiseEvent(Me, e)
  13.     End If
  14. End Sub