Dynamic Events on an ASP.NET Page
By Peter van Ooijen
Published: 4/3/2002
Reader Level: Beginner
Rated: 4.50 by 8 member(s).
Tell a Friend
Rate this Article
Printable Version
Discuss in the Forums

Building a web application has become a snap using Visual Studio.NET. You create an aspx webform, drag some controls from the toolbar and then customize  the controls in the properties window. That window has two tabs, one for the properties themselves and one for events. Properties have straight values like a color or size, but events stand for real code. This code is written in the programming language chosen for the project. I will choose C# to explore this world of .NET events.

Every event has an associated event handler, this is the piece of code which will execute when the event occurs. When the user clicks a button an OnClick event occurs and the associated OnClick method will run. .NET has a carefully designed model behind this. An object  is said to publish an event, methods of an object can subscribe to the event. A button publishes an OnClick event, a Button1_Click will subscribe to this publication. The publishing button will fire methods on the subscribers, Button1_Click will be executed when the user really clicks the button. This may sound an overcomplicated way to do get things done, but the nice thing in this model is that it is no problem at all for a publisher to have multiple subscriptions. This is also known as a multicast event. So when the user hits the button other subscribers than just your Button1_Click could be fired as well.

The method being fired by .NET components is of type void and has two parameters. The first parameter is the sender, this is the object which did fire the event. It is the button which was clicked. The second parameter is an object to hold arguments in which additional info can be passed from the publisher to the subscriber. The result type of the method in combination with the number and type of its parameters is called the signature of a method. In .NET a method signature can be declared as a type on itself and is called a delegate. From this delegate type subscriber objects can be created. The method to be executed when the subscriber gets notified by the publisher is passed as a parameter to the constructor of the delegate object.

In the core of the .NET class libraries is System.delegate, a base class to describe event signatures. This is a sealed class which means you cannot use classical OOP to create your own delegate classes. There is a point there, a delegate is only the declaration of a single method, without its class. Which is something which cannot really exist in .NET, as everything is an object in there. Instead the C# language has the delegate keyword to declare your method signature as it is. From this delegate you create delegate objects which subscribe to published event properties. System.EventHandler is a wrapper class round a delegate for the default (minimal) signature in a .NET event. The type is used for control properties like Click.

The .NET Framework has events everywhere and the handling of events in .NET offers some very interesting possibilities. In this article I will show how event handling methods are linked to webcontrols and how to (de-) couple these event handlers at runtime.

A webform with a button

I will create a new webform. On this webform is a list box and a button. In the button's properties window I select the events tab and doubleclick the action Click to enter the code editor. When the user clicks this button I want to add a message to the list box, so I code:

private void Button1_Click(object sender, System.EventArgs e)

{

       ListBox1.Items.Add("You clicked the button...");

}

Every time the button is clicked the list box grows. To clear the list box I will use a second button also with a Click action.

private void Button2_Click(object sender, System.EventArgs e)

{

       ListBox1.Items.Clear();

}

 

These two methods are event handlers. They contain code which is executed when the event, being with the click of a button, happens. Both methods have the System.EventHandler signature, a void method taking a parameter of type object and a parameter of type System.EventArgs. First I will dive deeper into sender, the first parameter. It is the object which fired the event. A button click is fired by a button, I should be able to get some button info out of this sender parameter.

private void Button1_Click(object sender, System.EventArgs e)

{

           System.Web.UI.WebControls.Button b = sender as System.Web.UI.WebControls.Button;

            if (null != b)

                ListBox1.Items.Add(string.Format("You clicked a button with caption '{0}'", b.Text));

            else

                ListBox1.Items.Add("You clicked something else");

}

The incoming sender object is typecasted to webbutton b using the as operator. The nice thing about this operator is that b will be set to a null value when the sender was not a Web button, without raising an exception. This is a good example of typesafety in .NET, a variable is either of the correct type, as declared, or null. Performing a hard typecast

           System.Web.UI.WebControls.Button b = (System.Web.UI.WebControls.Button) sender;

would raise an exception when the sender is not a Web button.

A generic eventhandler

Every event handler has the System.EventHandler signature. I will create a new method having this same signature, it will do exactly the same as the previous Button1_Click.

void ClickMe(object sender, System.EventArgs e)

{

      System.Web.UI.WebControls.Button b = sender as System.Web.UI.WebControls.Button;

      if (null != b)

         ListBox1.Items.Add(string.Format("You clicked a button with caption '{0}'", b.Text));

      else

         ListBox1.Items.Add("You clicked something else");

}

With the property editor you can set the event handing method of a control. In a dropdown all methods with the EventHandler signature will be shown. The ClickMe method I just wrote will be one of them.

I will add another control to the form, a Link Button. This control has a click action as well. The ClickMe method will appear again in its dropdown list and I will use this same method again.

Now two controls on my webform use the same event handling method. The result of clicking the controls can be seen in the list box.

Multiple event handlers responding to one event

So far just one method fired when an event happened. The nice thing about event handlers in .NET is that multiple methods can be executed when an event fires. The event handler has a collection of subscribed delegate objects and each delegate object has a method which will be fired. I need another event handling method to demonstrate this.

void JustAnotherEventHandler(object sender, System.EventArgs e)

{

      ListBox1.Items.Add("Event 1 says hello");

}

This method has to be connected to the event, the user clicking button1. In .NET speak my method will have to subscribe to the buttonClick publication. This is done by creating a subscribing delegate object. The method to be fired is passed as a parameter to the constructor. The System.Eventhandler class provides standard delegate objects.

void Page_Load(object sender, System.EventArgs e)

{

      // Put user code to initialize the page here

      Button1.Click+= new System.EventHandler(this.JustAnotherEventHandler);

}

A webform is initialized in the Page_Load method (which is actually an event as well). The delegate object is constructed using the JustAnotherEventHandler method. The object subscribes by adding itself with the += operator to the Button1.Click event. The result of this is that clicking the button will now result in two methods being executed, leading to two strings being added to the list box:

Passing data in the event

The second parameter of the event handling method is used to bring data from the publisher to the subscriber. This second parameter in System.Eventhandler is of type System.EventArgs, and cannot hold any data itself. It is a base class from which you can inherit to satisfy your needs. I will derive the MyEventArgs class from the System.EventArgs class, objects of my class pass a string to the subscriber of the event. This string is initialized in the constructor of my arguments class.

class MyEventArgs : System.EventArgs

{

    public string astring;

    public MyEventArgs(string a)

    {

        astring = a;

    }

}

A delegate is used to connect subscribing methods to a publisher. I need a delegate which understands MyEventArgs. It is declared straightforward way:

delegate void MyDelegate(object sender, MyEventArgs e);

This delegate describes the signature of methods which can be connected. So, I need a method which has this signature and does know what to do with MyEventArgs.

void ListString(object sender, MyEventArgs e)

{

    ListBox1.Items.Add(e.astring);

}

The method extracts a string form the incoming MyEventArgs object and adds it to the list box.

Now I have all the building blocks to create the MyEvent class. Objects of this class contain the data, know how to fire MyEvent and know how to fire a default event. I have to store and (later) execute a method, which can be handled by declaring a variable of type MyDelegate. This variable is assigned to in the constructor and is fired when the event occurs in the DoIt method:

class MyEvent

{

   private MyDelegate YouDoIt;

   private string param;

   public MyEvent(MyDelegate d, string p)

         {

            YouDoIt = d;

            param = p;

         }

   public void DoIt(object sender, System.EventArgs e)

         {

            YouDoIt(sender, new MyEventArgs(param));

         }

}

The data for the event is stored in the private param string. The method to be fired is stored in the private MyDelegate object YouDoIt. Both values are initialized  in the constructor of the MyEvent class.

The class has a method DoIt, this method has exactly the signature of the default EventHandler delegate. So it can be used to construct delegate objects for subscribing to a button click. The method DoIt will fire my own delegate passing it the original sender and a new MyEventArgs object based on the param string.

Now everything is ready to add this data sending event to the click of the button.

MyEvent mevent = new MyEvent( new MyDelegate(this.ListString),  "Just fooling..");

Button1.Click+= new System.EventHandler(mevent.DoIt);

A new MyDelegate object based on the ListString method is created. Together with a string constant it is used to construct a MyEvent object. This MyEvent object has the method DoIt which has the right signature to create a new System.EventHandler delegate object. Which will subscribe to the Button.Click event.

Clicking the button will now lead to three methods firing and three strings being added to the list box.

Adding it up : dynamically adding and deleting events

Every time the user clicks a button this leads to a roundtrip. On the webserver the page will be rebuild in the Page_Load method. This is the place to connect and disconnect additional event handling code. When doing so I can use the state of the controls on the webform to decide whether to connect. Text values in controls are used to construct MyDelegate objects. I will add three checkboxes on the form which will determine the setting of the handlers.

void Page_Load(object sender, System.EventArgs e)

{

   // Put user code to initialize the page here

   if (CheckBox1.Checked)

      {

         MyEvent mevent = new MyEvent(new MyDelegate(this.ListString), TextBox1.Text);

         Button1.Click+= new System.EventHandler(mevent.DoIt);

      }

   if (CheckBox2.Checked)

      {

         MyEvent mevent = new MyEvent(new MyDelegate(this.ListString), Label1.Text);

         Button1.Click+= new System.EventHandler(mevent.DoIt);

      }

   if (! CheckBox4.Checked)

         Button1.Click-= new System.EventHandler(this.ClickMe);

}

If one of the first two checkboxes is checked a new MyEvent object will be created and its DoIt method will subscribe at runtime to the Button1.Click event publisher. The data string needed in the constructor of MyEvent is read from a TextBox for the first event handler and from a Label for the other.

Button1.Click had one event handler set at design time, this was the ClickMe method. If the third checkbox is not checked a new delegate object based on ClickMe is created and this object will be subtracted from the Button1.Click event using the -= operator. The ClickMe method withdraws its subscription to the click event and will no longer be executed when the button is clicked.

Events in real world applications

For the sake of simplicity I have used a very basic webform and very basic event data. Included is a small demo application to play with events yourself. It is up to your imagination and needs to create any event handling code you can think of and construct any event data you might consider useful. At design time one event handling method can be set, at runtime you can rebuild the list of event subscribers again and again at every page_load. The strongest thing about events in C# is that they are multicast. When you have a background in Delphi you probably were familiar with event handlers which could be set at runtime. But with Delphi you could hook only one method at the time. In C# you can send your events out to anyone who wants to hear them.



Marketplace
(Sponsored Links)
What are the green links?
   



 
Copyright © 2007 CMP Tech LLC |
Privacy Policy (4/10/06) | Your California Privacy Rights (4/10/06) | Terms of Service | Advertising Info | About Us | Help