Event Driven ASP.NET Development with C#

Many of today’s most popular Web development platforms (PHP, ASP, Perl and Cold Fusion, among others) support Object Oriented Programming (OOP) concepts that help to keep Web application code well organized, modular, and scalable.

But there is another feature of modern programming languages that is less common among Web development platforms: Event Driven Programming (EDP). As one of the few Web development platforms to embrace both OOP and EDP, ASP.NET provides for an unmatched level of developer productivity on complex projects.

In this article, I’ll demonstrate the EDP features of ASP.NET and show you how to accomplish a few common Web programming tasks with EDP. While these skills are essential for any ASP.NET developer to learn, Web programmers who have worked with non-EDP platforms will want to pay especially close attention. EDP necessitates a very different approach to some fundamental issues. Habits formed while using other languages can easily translate to inefficient and unnecessarily convoluted ASP.NET code if you’re not fully aware of the power of EDP.

This article is the fourth in a series on ASP.NET. If you’re new to ASP.NET Web development and haven’t read my previous articles, check out Getting Started with ASP.NET, ASP.NET Form Processing Basics, and Object Oriented C# for ASP.NET Developers before proceeding.

Event Driven vs. Procedural Programming

Back in the days before the Graphical User Interface (GUI), most computer programs were written procedurally. A program would be a simple list of instructions (some of which would be conditional upon user input, for which the program would always stop to prompt the user). An icon of popular culture recently summed up procedural programming as follows: "Do this! Do that! Blah, blah, blah!"

The development of the GUI necessitated a more flexible programming model. Gone were the days when every user interaction could be reduced to a simple multiple-choice question or text prompt. GUI-based programs had to be able to react to a wide variety of events, from mouse clicks to background system activity (like a printer running out of paper) without interrupting the flow of whatever task the program was responsible for completing.

Just think — how smooth would a GIF animation look in a Web browser if, between each frame, the browser had to stop and check if the mouse had moved or been clicked? If any keys had been pressed? If the CD-ROM drive had been opened or closed? More importantly, how manageable would the code for the Web browser be? Enter Event Driven Programming.

These days, you can’t write a program for a graphical operating system such as Windows without understanding EDP, but until ASP.NET (and a few other pioneers, such as Macromedia Flash), the benefits of EDP were not available to Web developers.

"Why did all the other languages adopt archaic, procedural programming models?" you may wonder. ASP and PHP developers (myself included!), for instance, have grown accustomed to writing scripts with gigantic if statements of this form:

if (the user did this) 
{
 do this
}
else if (the user did this)
{
 do this
}
...
else
{
 do this
}

I can trace the reasoning behind this programming structure back to two sources:

The stateless nature of HTTP

Hypertext Transfer Protocol (HTTP), the protocol used for all communication between Web browsers and Web servers is stateless. Most server-side programming languages (ASP.NET included) support cookies and sessions and other such features designed to overcome this limitation, but when it comes right down to it, each request for a Web page remains a simple ask-and-answer cycle, essentially separate and independent from all others.

CGI and Perl, the Adam and Eve of server-side programming

When server-side programming was first conceived, the Common Gateway Interface (CGI) was the only way to do it. CGI is a standard whereby the Web server will run a specified program, wait for it to terminate, and send back the output of the program to the Web browser in response to its request.

Both HTTP and CGI are exceedingly simple standards that today’s Web applications use in incredibly complicated ways. The simplicity of these standards (run a program/script to produce the response for a browser request) suggests a simple programming model; but today’s applications demand something more robust.

Rather than a fixed list of instructions to follow, Event Driven Programming lets the developer identify a set of events for which the Web application should watch, and define how to react to each. Developers with a background in JavaScript will think this all sounds just a little too familiar. Indeed, ASP.NET code can look an awful lot like JavaScript code if you tilt your head just so.

Handling a Simple Event

As in JavaScript, Event Driven Programming in ASP.NET largely consists of writing event handlers — methods that run in response to events. While JavaScript has a healthy handful of events that you can handle, ASP.NET has hundreds, and that’s before you factor in the ability to add your own!

Let’s look at a really simple example with an event that will be familiar to JavaScript developers: a button click.

Here’s the code for ButtonTest.aspx:

<%@ Page Inherits="ButtonTest" src="ButtonTest.cs" %>  
<html>  
 <head>  
   <title> Event handler example </title>  
 </head>  
 <body>  
   <form runat="server">  
     <p>  
       <asp:Label runat="server" id="message">  
         Click the button!</asp:Label>  
     </p>  
     <p>  
       <asp:Button runat="server" id="button1"  
         Text="Click Me!" OnClick="ButtonClick" />  
     </p>  
   </form>  
 </body>  
</html>

As you can see, this is a simple ASP.NET page with an <asp:Label> (message) and an <asp:Button> (button1). The <asp:Button> has its OnClick attribute set to ButtonClick, which is the name of a method defined in the ButtonTest base class defined in the code behind file.

If you don’t understand the concept of code behind files, re-read the end of my previous article, Object Oriented C# for ASP.NET Developers. Here’s the code for ButtonTest.cs:

using System;  
using System.Web;  
using System.Web.UI;  
using System.Web.UI.HtmlControls;  
using System.Web.UI.WebControls;  
 
public class ButtonTest : Page  
{  
 protected Label message;  
 
 protected void ButtonClick(Object sender, EventArgs e)  
 {  
   message.Text = "Thanks for clicking!";  
 }  
}

All this class contains is the definition for ButtonClick and the Label field, message (which is required because ButtonClick refers to it). Like all .NET event handlers, the ButtonClick method takes two parameters and returns nothing (void). The first parameter will always contain the object that generated the event (in this case, button1), while the second parameter is used to pass any additional information about the event (none of the events we’ll see in this article use this).

Place these two files on your ASP.NET-enabled Web server and load up ButtonTest.aspx. As shown in Figure 1, clicking the button will trigger the event handler and display the new message.

The ButtonClick event handler responds to the clickFigure 1: The ButtonClick event handler responds to the click

As an experienced PHP developer, I would have expected to have to check to see if the button had been clicked in the page’s Page_Load method and respond to the click there. With support for EDP, however, ASP.NET lets you more naturally group together your event handling code.

Assigning Handlers in the Code Behind

While the previous example was fairly straightforward, it did have one sticking point. The event handler for the button was assigned in the .aspx file, violating the separation of design code and server-side logic that we have previously achieved with code behind files.

To improve this situation, we can instead assign the event handler in the code behind. The best place to do this is in the Page_Init method, which is called automatically by ASP.NET when the page is initialized (i.e. when the server loads it before processing the first request for it by a browser). Here’s the updated ButtonTest.cs, with changes shown in bold:

using System;   
using System.Web;  
using System.Web.UI;  
using System.Web.UI.HtmlControls;  
using System.Web.UI.WebControls;  
 
public class ButtonTest : Page  
{  
 protected Button button1;  
protected Label message;  
 
 protected void Page_Init(Object sender, EventArgs e)  
 {  
   button1.Click += new EventHandler(ButtonClick);  
 }  
 
 protected void ButtonClick(Object sender, EventArgs e)  
 {  
   message.Text = "Thanks for clicking!";  
 }  
}

Make the changes above, remove the OnClick attribute from the button1 tag in ButtonTest.aspx, and you should find that the example behaves exactly as before. Let’s examine what we’ve done here:

    button1.Click += new EventHandler(ButtonClick);

As you can probably guess, this line adds the ButtonClick method as a handler for the Click event of button1. But the syntax is somewhat mysterious, especially compared to the simple OnClick attribute it replaces!

All .NET events behave similarly to properties of their respective classes. So the Click event supported by all System.Web.UI.WebControls.Button objects is accessible in this case as button1.Click.

Now, any .NET event can have multiple handlers associated with it (i.e. multiple methods that will be triggered in sequence when the event occurs). So rather than assigning an event handler with the assignment (=) operator, we merely add an event handler to whatever existing handlers may exist (+=). .NET does not let you use the = operator with events, and any attempt to do so will result in a compilation error. You can also use the -= operator to remove event handlers, but that’s it.

As for the event handler itself, you may have expected to see something like this (I know I did!):

    button1.Click += ButtonClick; /* This is wrong */

The reason we must explicitly create an EventHandler object with the ButtonClick method (rather than directly assigning the method as an event handler) has to do with a confusing little detail of the C# language — delegates.

I’ll refer you to the C# Language Specification or a good book such as "Programming C#" (O’Reilly, 2001) for a complete discussion of delegates; however, here are the basics. A C# delegate is special type of class, objects of which contain a group of methods that have the same number and type of parameters and return the same type of value.

The System.EventHandler class is a simple example of a delegate. EventHandler specifies that it must contain methods that take two parameters (an Object and an EventArgs) and return void.

So as an event of type System.EventHandler, the Click event of the Button class requires us to assign it a delegate of type EventHandler. To do this, we create a new EventHandler object containing our ButtonClick method with the code new EventHandler(ButtonClick), and add it to the event.

Don’t fret too much if this is really not sinking in. Delegates were the hardest feature of C# for me to come to grips with, as it is not a feature you’ll easily find in other languages in popular use today. After awhile, the syntax just becomes second nature, and only advanced applications require an understanding of delegates beyond how to create event handlers with them.

Sharing an Event Handler

In many cases, you may wish to define a single event handler for multiple event sources. Since all event handlers receive a reference to the source of the event, they can determine which of the multiple sources originated the event and act accordingly.

Consider the following, updated version of ButtonTest.aspx:

<%@ Page Inherits="ButtonTest" src="ButtonTest.cs" %>    
<html>    
 <head>    
   <title> Event handler example </title>    
 </head>    
 <body>    
   <form runat="server">    
     <p>    
       <asp:Label runat="server" id="message">    
         Click a button!</asp:Label>    
     </p>    
     <p>    
       <asp:Button runat="server" id="button1"    
         Text="One" />    
       <asp:Button runat="server" id="button2"    
         Text="Two" />    
       <asp:Button runat="server" id="button3"    
         Text="Three" />    
     </p>    
   </form>    
 </body>    
</html>

We now have three buttons to choose from, and we’d like to display a different message upon clicking each. Here’s the updated code behind file, ButtonTest.cs:

using System;    
using System.Web;    
using System.Web.UI;    
using System.Web.UI.HtmlControls;    
using System.Web.UI.WebControls;    
public class ButtonTest : Page    
{    
 protected Button button1;    
 protected Button button2;    
 protected Button button3;    
 protected Label message;    
 protected void Page_Init(Object sender, EventArgs e)    
 {    
   EventHandler clickHandler =    
     new EventHandler(ButtonClick);    
   button1.Click += clickHandler;    
   button2.Click += clickHandler;    
   button3.Click += clickHandler;    
 }    
 protected void ButtonClick(Object sender, EventArgs e)    
 {    
   if (sender is Button)    
   {    
     Button clickedButton = (Button)sender;    
     message.Text = "You clicked: " + clickedButton.Text;    
   }    
}    
}

We’ve added references to our two new buttons, and assigned our EventHandler to a variable (clickHandler), which we then add to the Click events of all three buttons. Finally, I’ve modified the ButtonClick method to display the name of the button that the user clicked. Let me walk you through the code, as it uses a couple of tricks I have not discussed before.

    if (sender is Button)    
   {

The ButtonClick method will always be called with the source of the event in the sender parameter. That parameter is of type Object, which is the base class of the .NET Framework (i.e. all classes are subclasses of System.Object). To display the name of the button that was clicked, we need to treat this parameter as a Button — not just a mere Object. Before doing so, we must check to be sure that the sender parameter is indeed a Button object, despite being stored in a variable of type Object.

Note: This ability for any object to be stored in a variable of the same class or any of its base classes (a.k.a. superclasses) is actually a feature of modern object oriented languages called polymorphism. In the previous article, this same feature allowed us to treat objects of class CoconutTree just like objects of class Tree if we wanted to.

To check that the object stored in sender is of class Button (or any subclass thereof), we use the is operator in C#. The syntax is relatively self-explanatory; if sender contains an object that can be treated as a Button, then sender is Button will be true.

      Button clickedButton = (Button)sender;

Since we’ve checked that sender contains a Button, we can create a variable of type Button and store the value of sender into it. Since, as far as C# knows, sender is just an Object, and you can’t store an Object in a Button variable, we need to tell C# to take the value in sender and convert it to a Button. This is done by enclosing the type to convert to in parentheses and putting it before the variable name, as we’ve done here.

This explicit conversion of a value from one type to a more complex type is called casting. An experienced C# programmer would say that we are "casting sender to a Button" on the above line.

Finally, now that we have our clicked button in the clickedButton variable, we can use its label to display an appropriate message:

      message.Text = "You clicked: " + clickedButton.Text;

See Figure 2 for the results, or try the script on your own server!

Same event handler, multiple outcomesFigure 2: Same event handler, multiple outcomes

Postback vs. Non-Postback Events

As I mentioned above, there are literally hundreds (if not thousands) of events scattered throughout the .NET Framework to which you can react with event handlers. Some of the events occur as a result of user activity (e.g. the Click event we’ve experimented with so far), while others are generated by ASP.NET itself (e.g. a database item getting inserted into a DataGrid control). Of the user-generated events, there are two types:

  • Postback Events that are immediately reported to the Web server via a form submission (e.g. buttons, hyperlinks, etc.).
  • Non-Postback Events that the browser takes note of but doesn’t report until the next form submission (e.g. checkbox, radio button, and list selections, text entries, etc.).

To demonstrate this, let’s switch from using Buttons to RadioButtons in our example. Here’s the .aspx:

<%@ Page Inherits="ButtonTest" src="ButtonTest.cs" %>     
<html>    
 <head>    
   <title> Event handler example </title>    
 </head>    
 <body>    
   <form runat="server">    
     <p>    
       <asp:Label runat="server" id="message">    
         Choose an option!</asp:Label>    
     </p>    
     <p>    
       <asp:RadioButton runat="server" id="button1"    
         Text="One" GroupName="radioGroup" /><br />    
       <asp:RadioButton runat="server" id="button2"    
         Text="Two" GroupName="radioGroup" /><br />    
       <asp:RadioButton runat="server" id="button3"    
         Text="Three" GroupName="radioGroup" /><br />    
     </p>    
     <p>    
       <asp:Button runat="server" id="submitButton"    
         Text="Submit" />    
     </p>    
   </form>    
 </body>    
</html>

In this example, we have three <asp:RadioButton> tags, all of which share the same GroupName. This will create a group of three radio buttons, of which only one may be selected at a time.

Here’s the code behind file:

using System;     
using System.Web;    
using System.Web.UI;    
using System.Web.UI.HtmlControls;    
using System.Web.UI.WebControls;    
   
public class ButtonTest : Page    
{    
 protected RadioButton button1;    
 protected RadioButton button2;    
 protected RadioButton button3;    
protected Label message;    
   
 protected void Page_Init(Object sender, EventArgs e)    
 {    
   EventHandler selectionHandler =    
     new EventHandler(RadioChange);    
   button1.CheckedChanged += selectionHandler;    
   button2.CheckedChanged += selectionHandler;    
   button3.CheckedChanged += selectionHandler;    
 }    
   
 protected void RadioChange(Object sender, EventArgs e)    
 {    
   RadioButton checkedButton = null;    
   if (button1.Checked)    
     checkedButton = button1;    
   else if (button2.Checked)    
     checkedButton = button2;    
   else if (button3.Checked)    
     checkedButton = button3;    
   if (checkedButton != null)    
     message.Text = "You selected: " + checkedButton.Text;    
 }    
}

As you can see, RadioButton objects have a CheckedChanged event of type EventHandler that is fired whenever the radio button in question changes its selection state. By assigning the same event handler (selectionHandler) to the CheckedChanged event of all three radio buttons, we can be notified whenever the user selects a new radio button from the list.

But since the CheckedChanged event is not a Postback Event, it doesn’t fire until the next form submission, which is why we still need an <asp:Button> to submit the form.

Fortunately, most ASP.NET controls that have Non-Postback Events, RadioButton included, also have an AutoPostBack property that changes all of its events into Postback Events. Thus, by merely setting the AutoPostBack property of the three radio buttons to true, we can do away with the submit button:

<%@ Page Inherits="ButtonTest" src="ButtonTest.cs" %>     
<html>    
 <head>    
   <title> Event handler example </title>    
 </head>    
 <body>    
   <form runat="server">    
     <p>    
       <asp:Label runat="server" id="message">    
         Choose an option!</asp:Label>    
     </p>    
     <p>    
       <asp:RadioButton runat="server" id="button1"    
         Text="One" GroupName="radioGroup"    
         AutoPostBack="true" /><br />    
       <asp:RadioButton runat="server" id="button2"    
         Text="Two" GroupName="radioGroup"    
         AutoPostBack="true" /><br />    
       <asp:RadioButton runat="server" id="button3"    
         Text="Three" GroupName="radioGroup"    
         AutoPostBack="true" /><br />    
     </p>    
   </form>    
 </body>    
</html>

As shown in Figure 3, the message now updates as soon as the user selects one of the radio buttons.

CheckedChanged becomes a Postback Event with AutoPostBack=Figure 3: CheckedChanged becomes a Postback Event with AutoPostBack="true"

Summary

In this article, I demonstrated the basics of Event Driven Programming (EDP) in ASP.NET. I explained the advantages of EDP over more traditional server-side programming techniques, and made sure to assign the event handlers in the code-behind file, to maintain the separation between design and server-side logic. I showed how to use a single event handler with multiple event sources, and finished up by distinguishing Postback and Non-Postback events.

While I’ve covered the basics here, events are far more deeply integrated into the structure of ASP.NET than the simple examples we have seen may suggest. In a future article, where I’ll show how to display database information on the Web with ASP.NET, we’ll revisit the subject of events to provide formatting for various data items in a table. In another article, I’ll explain all the different events that you need to be aware of when building custom ASP.NET Web Controls.

In my next article, however, I’ll cover techniques for form validation in ASP.NET. Once again, where most other server-side languages leave you to fend for yourself, ASP.NET comes equipped with a rich set of tools that do most of the work for you. If you’ve ever written JavaScript form validation code by hand, you won’t want to miss this article!

Free book: Jump Start HTML5 Basics

Grab a free copy of one our latest ebooks! Packed with hints and tips on HTML5's most powerful new features.

No Reader comments

Comments on this post are closed.