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:

  1. define a delegate type that specifies the signature of the event handler
  2. define an event based on the delegate type defined in 1
  3. define a protected virtual method that raises the event
  4. invoke the method defined in 3 when the event occurs
Subscribing to an event

To subscribe to and handle an event a subscriber must:

  1. implement an event handler with the signature specified by the delegate object of the event
  2. create a delegate object for the event that refers to the event handler method
  3. 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:

  1. By overriding the virtual, protected method of the base class
  2. By attaching a delegate to the event (as introduced above)
  3. 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:

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
  1. Load is the name of the event.
  2. AddHandler is the keyword that hooks up the event.
  3. 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