View Single Post
Old 07-13-2008, 04:48 PM
AtmaWeapon's Avatar
AtmaWeapon AtmaWeapon is offline
Fabulous Florist

Forum Leader
* Guru *
Join Date: Feb 2004
Location: Austin, TX
Posts: 9,500

How do I define my own events?
This is actually pretty easy, especially if you keep the conventions discussed above in mind. There's some conventions that are to be followed when you make your own events, and if you follow them your events will be easier for other programmers to understand. There's 6 steps to follow to create your own event.

Step 1: Name the event
This is usually simple. Think of a name for the event. Usually, the name is something that could be used for the answer to the question, "What happened?". For example, some of the events on the Form class are FormClosing, SizeChanged, and Load. Each of these events describes what happens to cause the event to be raised. For the purposes of this example, let's say we are going to name our event SomethingHappened, despite the fact that this is a horrible name since it's very vague.

Step 2: Decide if you need a custom EventArgs
Does the fact that your event happened give the subscriber enough information, or do you need to provide more information? If you don't need to provide any custom information, go on to step 3. If you need to provide information to accompany the event, then you'll need to define your own custom EventArgs-derived class for the event, so go to step 2a. If you're confused, consider the MouseUp event as an example: when this event is raised, the user might need to know what button was released and where the button was released. This information can't be provided by EventArgs, so it is passed via the MouseEventArgs class. If you need to pass information like this, go to step 2a.

Step 2a: Define your custom EventArgs
You need a custom class to provide information about the event. This class must ultimately derive from EventArgs, or you won't be able to match the EventHandler(Of T) delegate. There are a few rules you should follow for this class:
  • Name the class <eventName>EventArgs; for the SomethingHappened event this should be named SomethingHappenedEventArgs. This makes the purpose of the class and its connection to the event clear. The exception is if your EventArgs class is going to be used for multiple events; in this case, name it something that clearly relates it to the class of events that use it. A good example is MouseEventArgs, which is used for events that are raised by mouse activity.
  • Express the information in the class as read-only properties. The EventArgs should only have writable properties if you need subscribers to send some information back to the event source; CancelEventArgs is a good example of a class that does this.
  • Provide a constructor that lets the caller set each property. Since the information in the class is supposed to be read-only, this is the only chance to set the properties of the class. Be sure to call the base-class constructor, particularly if you don't derive directly from EventArgs (for example, if you derive from CancelEventArgs you have to provide the parameters for its constructor and call it.)

Now that you have your custom EventArgs class, you can move on to step 3.

Step 3: Declare the event
Now you need to declare your event in the event source class. Look back to the section about how the events work for more guidance here. For our SomethingHappened event, assuming we went through step 2a, the event declaration might look like this:
Public Event SomethingHappened As EventHandler(Of SomethingHappenedEventArgs)
You don't have to make events public, but keep in mind that if the event is not public then you are limiting who can subscribe to the events. Private events are not necessarily a bad idea, but it's generally more clear to call a private method.

Step 4: Declare an OnEvent method
This is not required, but is part of the general event-declaring conventions in the .NET framework. You need to define a method in your event source that is named On<eventName> and takes the appropriate EventArgs parameter. This method should be Protected if you want derived classes to be able to override it or Private if you don't want derived classes to fool with it. Don't make the On<eventName> method public, or else any other class can cause your event to be raised for no reason!

This method is responsible for raising the event, and performing any housekeeping that goes along with it. For example, if your class wants to do something before or after an event is raised, you can make sure to put that code before or after the RaiseEvent in this method.

Here's an example OnSomethingHappened:
Private Sub OnSomethingHappened(ByVal e As SomethingHappenedEventArgs)
    RaiseEvent SomethingHappened(Me, e)
End Sub
You can find lots of methods like this on the Form class. For example, to handle the Load event, you can override the OnLoad method:
Protected Overrides Sub OnLoad(ByVal e As EventArgs)
End Sub
It is very important that you call the base class OnEvent method if you override it. The base class method is responsible for raising the event, and your override method is the one that will be called. If you do not call the base class method yourself, it will never get called and the event will not be raised! Occasionally, this is desirable and you will do it purposefully, but in general it's not a good thing.

Step 5: Raise the event when needed.
Now, you have the framework to raise the event in place. You need to put calls to OnEvent in your code whenever you need the event to be raised. If you have a custom EventArgs class, you'll need to create an instance to pass along with the event. To raise the SomethingHappened event, our code might look like this:
Dim args As New SomethingHappenedEventArgs("explosion")
Step 6: Subscribe to the event.
Now, your event source class will notify any subscribers whenever the event is raised. The only thing left to do is to have event handlers subscribe to the event! See the section titles, "How do I subscribe to Events?" for more information.

I've attached a zip file that contains an example project for VS 2008 and VS 2005. The VS 2005 solution is named "EventDemo.2005.sln". It MIGHT not compile in VS 2005 right off of the bat; I don't have VS 2005 installed to test, and there's some syntax that VS 2008 lets by even if you target .NET Framework 2.0 that doesn't fly in VS 2005. Please let me know if it doesn't compile and I'll fix it. The Counter class is the event source. It has a Count method that counts from 1 to the number you specify. The CountUpdate event is a custom event that is raised whenever the Count method counts a new number. CountUpdate needs to notify its subscribers of the number that was counted, so it uses CountUpdateEventArgs instead of EventArgs. MainForm creates a Counter and calls Count on a new thread after subscribing to the CountUpdate event (a thread is necessary so the UI doesn't lock up.) When the event is raised, the event handler MainForm.HandleCounterCount is called; it adds a timestamp to the number that's counted and calls the UpdateTextBox method. UpdateTextBox does some threading acrobatics, but ultimately updates the text box every time the event is raised. This should give you a good idea of what defining an event looks like.

But wait! There's more!
A few months ago, I posted an Advanced Events Tutorial. It covers some problems with the way VB .NET sets up your events by default, and discusses some advanced syntax for solving these problems. You probably won't need the information in that thread unless you're making classes that should be thread-safe or with more than about 5 or 6 events, but if you feel adventurous you should give it a look.
Attached Files
File Type: zip (21.7 KB, 138 views)

Last edited by Colin Legg; 10-31-2008 at 02:24 PM.
Reply With Quote