This article is part three of three about the use of the Share keyword. Part one, Shared and Instance Members in VB.NET, covered the more frequently used shared methods and properties in VB.NET. Part two, Shared Variables in VB.NET, covered shared variables - not a well known technique. Part three, this article, covers the use of shared events. There is a specific case - when parameterized constructors have to be used - when shared events are useful. This article shows how it's done.
Coding events can be confusing too. Of course, events are used constantly in VB.NET but the code for declaring them, handling them, and raising them is generally hidden and they work so well that you just don't find a need to understand how it's all done behind the scenes very often. But if you do have a need, there's a whole series of articles about coding events that starts here: Events Using Your Own Code in VB.NET
To have a starting point, here's the most basic event processing code I can think of:
Public Class Form1
WithEvents theEventClass As New theClass
Private Sub Form1_Load(
sender As System.Object,
e As System.EventArgs
) Handles MyBase.Load
theEventClass.EventSub()
End Sub
Private Sub HandleTheEvent() _
Handles theEventClass.theEvent
Console.WriteLine("theEvent handled")
End Sub
End Class
Public Class theClass
Public Event theEvent()
Public Sub EventSub()
RaiseEvent theEvent()
End Sub
End Class
In fact, the class that is instantiated, theClass, is so basic that it only contains the minimum event processing code. Let's add a little more to that class, and - more significantly here - change the modifier of the event to "Shared".
Public Class theClass
Shared Event theSharedEvent()
Public Property theProperty As Integer
Public Sub NonSharedSub()
theProperty = 54321
RaiseEvent theSharedEvent()
End Sub
End Class
The code still works! This leads us to the first rule. A shared event can be raised by a shared or non-shared method. No difference. We'll see later why this is important.
The code was also upgraded a bit to reflect the other changes, but these don't affect the logic. Here's the revised event handler code:
Private Sub HandleTheEvent() _
Handles theEventClass.theSharedEvent
Console.WriteLine("theEvent handled: " &
CStr(theEventClass.theProperty))
End Sub
Lets add a shared method now and see how that works.
--------
Click Here to display the illustration
--------
It doesn't work too well. The shared method can't access the property. So, let's change the property to shared and see how that works.
--------
Click Here to display the illustration
--------
That doesn't work either! Now the event handler code can't access the property. It's a problem either way. What can you do about that?
Like so many things in programming, the answer isn't even a part of anything you have changed so far. The answer is that shared events can't use the "Handles / WithEvents" keywords. You have to use an AddHandler statement instead.
AddHandler _
theClass.theSharedEvent,
AddressOf HandleTheEvent
But your problems aren't over yet. Now, the compiler is complaining that, "Reference to a non-shared member requires an object reference." when the code references "theClass.NonSharedSub()". (Before, it was executing the sub in the class directly ... functionally about the same as a shared sub.) So you have to instantiate the class and reference the instance instead. Both of these (in this program) are done in the form load sub.
Private Sub Form1_Load(
sender As System.Object,
e As System.EventArgs
) Handles MyBase.Load
AddHandler _
theClass.theSharedEvent,
AddressOf HandleTheEvent
Dim anInstanceClass As New theClass
anInstanceClass.NonSharedSub()
theClass.SharedSub()
End Sub
Note that both shared and non-shared methods are executed from the class, and both raise the same shared event.
--------
Click Here to display the illustration
--------
To illustrate why this can be important, suppose your code required a parameterized "New" constructor. For this example, let's pass a value that will be saved in the shared property.
Public Sub New(PropVal As Integer)
theProperty = PropVal
RaiseEvent theSharedEvent()
Console.WriteLine("New Constructor Executed")
End Sub
If you're using a shared method, then a parameterized constructor is a required, non-shared method that must be in the same class. That's exactly what has already been demonstrated, so this allows you to use the shared event in the constructor.
--------
Click Here to display the illustration
--------
The illustration shows the code in action in a generic form. But you may need this kind of code if you want your constructor to trigger some specific action somewhere else, such as logging the creation of objects. You might also want to count object creation. The key is knowing that it's available when you do need it.
