Custom Event Handlers in ASP.NET 2.0

16 October, 2005 (06:53) | Asp.Net 2.o

This week I came across an issue that took a little bit of research to figure out. So for posterity, here is a solution that worked.

When working with user controls it frequently becomes necessary to notify the container of the user control that some event occurred within the control itself. Especially when the result of this event means that the control expects the container to react in some way. For example take a user control that shows a paged result list. Maybe its composed of a datalist or repeater and a way to select a specific page in the results. Many applications limit the results shown in lists to some standard number – like 25 rows, in order to prevent the page from having to render hundreds and hundreds of rows in one shot.  Our control – in order to be useful - resides on a page and receives its data from the page itself. That approach tends to make the control a bit more agnostic. So in my hypothetical situation, the page loads and hands the first 25 rows of a result set to the user control. Here comes the kicker. What happens if the end user clicks on a link to see page 2 or 3  of the resultset. How does the control tell its provider of data (the page), that it now needs a different set of rows? Custom Events to the rescue. By wiring the user control with an event that fires whenever additional data is needed the page can intercept the event, execute the data access and hand the user control its next 25 rows of data.

ASP.NET 2.0 seems to entail a couple of small changes that caused none of my previously successful ideas of custom events (with and without delegates) to work. After a bit of hacking , here is a sample that worked. In good part thanks to Bilal Haidar

Here is some code from a user control. Lets say that you have a drop down list that contains the number of pages

… section omitted for brevity

// First the snippet that wires a local event to our custom event handler.
// if someone changes the page selection, fire a custom event to the parent container
protected void  ddlPager_SelectedIndexChanged(object sender, EventArgs e)
{
   OnPagerClick(e)
}

// Here is section of custome event handling code that reacts to the pager control click
// and telegraphs that event to a page for example
private static readonly object EventRequeryNeeded = new object();

    public event EventHandler RequeryNeeded
    {
        add
        {
            Events.AddHandler(EventRequeryNeeded, value);
        }
        remove
        {
            Events.RemoveHandler(EventRequeryNeeded, value);
        }
    }

    protected virtual void OnPagerClick(EventArgs e)
    {
        EventHandler RequeryNeeded = (EventHandler)Events[EventRequeryNeeded];
        if (RequeryNeeded != null)

           //bubble up the entire pager control and its arguments
            RequeryNeeded(this.ddlPager, e);
    }

 

Thats all the code needed in the user control. The only thing left to do is to wire up the page that will hold the user control so that it may respond to the 
custom event.

The page registers the user control in the usual way and references it in HTML as well

<%@ Register TagPrefix=”ExampleCtl” TagName=”uc1″ Src=”OurUserControl.ascx” %>

 <ExampleCtl:uc1 runat=”server” id=”ucRequeryTest”/>

In the code behind of the page, the user control’s custom event gets wired up – look at the Page_Init() method.
This method tells the page that whenever the control fires its custom event, the page needs to run a method called
ucRequeryTest_RequeryNeeded(object sender, EventArgs e). Of course within that method we can interrogate the sender and
find out what the pager drop down was set to – the new page value .

Imagine the sequence – page loads, gets some data and hands it to the user control. Control takes data and wires up the list
display (repeater, datalist whatever). I didnt get into the details of the pager getting its number of pages. Lets assume
that magically the pager drop down has a list of Page 1, Page 2, Page 3 etc. Now the user clicks on this pager and moves it to
Page 3. The custom event in our user control fires and tells its container page to do something. Voila.
The page intercepts the event, runs its own private method that was defined in the Page_Init() handler declaration and your off to
the races. The page now has everything needed to respond to this change in the control.

using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class Home : System.Web.UI.Page
{

    protected void Page_Load(object sender, EventArgs e)
    {
      //Nothing going on here    }

    private void ucRequeryTest_RequeryNeeded(object sender, EventArgs e)
    {
       DropDownList ddl = (DropDownList)sender;
       DoSomeWildDataRetrievalForTheSelectedPage(Int32.Parse(ddl.SelectedItem.Value));
    }

    void Page_Init()
    {
        ucRequeryTest.RequeryNeeded += new EventHandler(ucRequeryTest_RequeryNeeded);
    }
}

 

Write a comment