Event Handling in ASP.NET...
The ASP.NET model hides the programmer from some of the full complexities of event handling in VB.NET, as does
the IDE of VS.NET so this article shall hopefully provide a little insight into what's available in the .NET
framework.
By: Chris Sully
Date: June 21, 2003
Introduction
If you're programming ASP.NET web forms you are using and handling events already, for example when you code
against a form button click. In fact they are central to the ASP.NET programming model. Not all events are
triggered by end user action: modifications to a file, changes in time and completion of program execution are
also examples of events you may decide to code against. Plus you can raise your own events if you so choose.
The ASP.NET model hides the programmer from some of the full complexities of event handling in VB.NET, as does
the IDE of VS.NET so this article shall hopefully provide a little insight into what's available in the .NET
Framework. Before we deal with implementation specifics I shall look at some of the general issues surrounding
event handling, presented in the .NET context.
Concepts of Event Handling
Event arguments
The event arguments specify the data associated with an event. When an event is raised the event arguments are
passed to the event handlers. With this data they have sufficient information to handle the event. Event
arguments are of type EventArgs, or one of its derived types.
Event Handlers
An event handler is a method that performs custom actions in response to an event notification provided by the
event of a class. This handler must take as parameters exactly the values that the event generates. By convention
an event handler returns no data and takes two parameters. The first specifies the object on which the event
occurred (the publisher of the event). The second contains the event arguments as described above.
Delegates
A delegate is a special class allowing creation of objects capable of referencing methods with a particular
signature. For example:
|
Public Delegate Sub EventHandler(ByVal sender As Object, ByVal e As EventArgs) (1)
|
Here EventHandler is a delegate: an object capable of storing a reference to any method that has no return value
and that accepts two arguments, one of type Object and the other of type EventArgs.
Why are delegates important to event handling? ASP.NET uses delegates to attach code to events, as we'll see by
example shortly.
Events
Turning back to an overview of events to put the terms defined above in context. An event enables objects in a
class to notify other objects that something has happened that they should perhaps react to. Events in VB.NET
are based on a publisher-subscriber model. The class that implements an event is called the publisher of that
event. A subscriber class can subscribe to a published event by registering an appropriate event handler with
the published event. Then when an event is raised the publisher notifies all registered objects about the event
by invoking the registered event handlers.
For example, the Page class notifies other objects that a page is about to render its content using the
PreRender event. The definition of the PreRender Event in the Page is:
|
Public Event PreRender As EventHandler (2)
|
This defines the PreRender event as being of type EventHandler where EventHandler, as defined above in (1), is a
Delegate. The Delegate type determines the signature of the event handlers that can be registered with an event.
You register an event handler with an event by encapsulating the event handler in a delegate object and adding
the delegate to the event, e.g.: you could code the following within an ASP.NET page:
|
AddHandler Me.Render, AddressOf Me.Page_PreRender (3)
|
Here the Me keyword represents the page object. A reference to the address of the method is passed to the event.
The preceding statement (2) first encapsulates the reference to the Page_PreRender method in a delegate object
of compatible type and the AddHandler syntax then adds this delegate object to an event.
The event internally manages a linked list of delegates registered to it. As well as the AddHandler method you
have RemoveHandler that can be used to disassociate a handler with an event. When an event is raised, its linked
list of delegates is scanned to invoke the event handlers encapsulated in the delegate objects.
Event Raising Methods
Each class that publishes an event also provides a protected, virtual method that raises the event. When the
specific incident occurs the publisher class invokes this method. The task of this method is to notify all the
event subscribers about the event.
The event raising methods are identifiable via their naming convention � the word 'On' followed by the name of
the event, e.g. OnPreRender.
Process Summary
Now that we've looked at some of the detail let's summarise the processes of publishing and subscribing to an
event.
Publishing an Event
To publish and raise an event a publisher must:
- define a delegate type that specifies the signature of the event handler
- define an event based on the delegate type defined in 1
- define a protected virtual method that raises the event
- invoke the method defined in 3 when the event occurs
Subscribing to an event
To subscribe to and handle an event a subscriber must:
- implement an event handler with the signature specified by the delegate object of the event
- create a delegate object for the event that refers to the event handler method
- attach the event handler to the event
Event Handling in ASP.NET
Now that we've examined some of the general concepts we can turn to the practicalities of event handling in
ASP.NET via a consideration of three techniques for handle events in ASP.NET:
- By overriding the virtual, protected method of the base class
- By attaching a delegate to the event (as introduced above)
- Through AutoEventWireUp of the Page class
In the process we shall hopefully also reinforce the ideas presented above.
By overriding the virtual, protected method of the base class
You will know that an ASP.NET web form inherits from the Page class and hence includes a set of events and
(virtual protected) methods for raising those events. For example, OnInit() is the method of the Page class that
raises the Init event. When an ASP.NET page is first created and initialised, it automatically invokes the
OnInit() method which in turn raises the Init event corresponding to the recently initialised Page object and
passes any required event related data to the Init event.
As your page is derived from the Page class you can override the event-raising protected method of the base
class that publishes the event, as follows:
Protected Overrides Sub OnInit(e as EventArgs)
Response.Write("OnInit Event method fired!")
MyBase.OnInit(e)
End Sub
|
Note the MyBase.OnInit(e) call which makes sure the base method is also called in addition to any functionality
you wish to present.
Remember that this technique of handling events can only be used in the derived class of the class that publishes
the event. If you want to subscribe to events from a class that does not derive from the class that publishes
events, you have to use the next described technique that handles events by attached delegates.
By attaching a delegate to the event
This method provides far more flexibility because:
- Delegates allow you to attach a single event handler to several events. This technique eliminates extra
coding efforts when you have to take similar actions when different events occur.
- Delegates allow you to dynamically add and remove event handlers for an event. You may also associate
multiple event handlers with an event.
- The subscriber class is not required to derive from the class that publishes an event.
This is the method preferred within VS.NET, where the additional step of attaching the delegate is automated.
Here's a relatively simple hand coded ASP.NET example:
<%@ Page Language="VB" %>
<script runat="server">
' Insert page code here
Protected Sub CustomLoadEvent(sender as Object, e as EventArgs)
Response.Write("Message from load event handler!")
End Sub
Protected Overrides Sub OnInit(e as EventArgs)
AddHandler Me.Load, AddressOf Me.CustomLoadEvent
MyBase.OnInit(e)
End Sub
</script>
<html>
<head>
</head>
<body>
<form runat="server">
<!-- Insert content here -->
</form>
</body>
</html>
|
Don't be confused by the use of the OnInit method, particularly following the last example � this is just a
convenient location to define the event handler. Breaking down:
|
AddHandler Me.Load, AddressOf Me.CustomLoadEvent
|
- Load is the name of the event.
- AddHandler is the keyword that hooks up the event.
- CustomLoadEvent is the name of the event handler.
Here is what is happening:
The Init event is raised when an ASP.NET page is initialized. This is just a convenient location to define the
event handler. An event handler is attached to the page load event. When the Page Load event fires the
corresponding defined event handlers are invoked. An event handler can be attached to the load event only
through its delegate object. So where are the delegate and event definitions? Well, slightly confusingly, these
are hidden as they are already available as part of the Page class as follows:
Public Delegate Sub EventHandler(sender as object, e as EventArgs)
Public Event Load As EventHandler
|
Here the signature of the CustomLoadEvent event handler method matches the criteria of the EventHandler delegate
and hence a reference to CustomLoadEvent can be stored in an instance of delegate type EventHandler.
When you have such an instance of the EventHandler delegate you can attach it to the event with the AddHandler
keyword. When the load event is raised the CustomLoadEvent method is invoked via its reference as maintained by
the delegate object.
Confused? It can be a confusing subject but if you forget the terminology and about what .NET is doing behind the
scenes, you could simply accept the syntax of
|
AddHandler Me.Load, AddressOf Me.CustomLoadEvent
|
at face value ... that it is simply adding an event handler to the Load event which will cause the CustomLoadEvent
sub to be executed when the Load event fires.
Through AutoEventWireUp of the Page class
AutoEventWireUp relies on using specific names for the event handlers of Page class events. The name has to be
of the form Page_EventName, e.g. Page_Init. The AutoEventWireUp attribute of the Page directive must be set to
true, which is the default in ASP.NET but will be set to false in VS.NET.
Thus the following code will produce no output:
<%@ Page Language="VB" AutoEventWireUp="false"%>
<script runat="server">
Protected Sub Page_Load(o as object, e as EventArgs)
Response.Write("Message from load event handler!")
End Sub
</script>
<html>
<head>
</head>
<body>
<form runat="server">
<!-- Insert content here -->
</form>
</body>
</html>
|
but if you set AutoEventWireUp="true" which is the default, the Page_Load Sub will be executed. Which is probably
how many of you non VS.NET ASP.NET programmers have been developing for some time now anyway.
Conclusion
I hope this article is a reasonably clear and comprehensible introduction to some aspects of the use of events
with ASP.NET / VB.NET. Look out for another article on DotNetJohn where I'll focus on a more complex example
where events come in useful.
References
ASP.NET: Tips, Tutorial and Code
Scott Mitchell et al.
Sams
Developing and implementing web applications with VB.Net and VS.Net
Mike Gunderloy
Que