views:

756

answers:

2

Background: I am customizing an existing ASP .NET / C# application. It has it's own little "framework" and conventions for developers to follow when extending/customizing its functionality. I am currently extending some of it's administrative functionality, to which the framework provides a contract to enforce implementation of the GetAdministrationInterface() method, which returns System.Web.UI.Control. This method is called during the Page_Load() method of the page hosting the GUI interface.

Problem: I have three buttons in my GUI, each of which have been assigned an Event Handler. My administration GUI loads up perfectly fine, but clicking any of the buttons doesn't do what I expect them to do. However, when I click them a second time, the buttons work.

I placed breakpoints at the beginning of each event handler method and stepped through my code. On the first click, none of the event handlers were triggered. On the second click, they fired.

Any ideas?

Example of Button Definition (within GetAdministrationInterface)

public override Control GetAdministrationInterface()
{
    // more code...

    Button btn = new Button();
    btn.Text = "Click Me!";
    btn.Click += new EventHandler(Btn_Click);

    // more code...
}

Example of Event Handler Method Definition

void Btn_Click(object sender, EventArgs e)
{
    // Do Something
}

Page_Load Method that calls GetAdministrationInterface

protected void Page_Load(object sender, System.EventArgs e)
{
    if (!Page.IsAsync)
    {
        List<AdministrationInterface> interfaces = <DATABASE CALL>;
        foreach(AdministrationInteface ai in interfaces)
        {
            placeholderDiv.Controls.Add(ai.GetAdministrationInterface());
        }
    }
}
A: 

Whilst its hard to know exactly without seeing the full Page_load method it does smell a little bit like the event handlers are not hooking up until the page is reloaded.

eg:

if (IsPostBack) { // Add handlers here ... }

Simon Rigby
+2  A: 

Good grief! I knew it was going to be something this stupid. Purely my fault of course and my lack of knowledge in ASP .NET.

After doing a multitude of Google searches and eventually being blocked by Google on suspicion of being a bot running automated scripts, I managed to squeeze in one last search in and stumbled across this article. Already at the point of giving up, I tried my best to read the article without skipping 10 lines at a time or looking for pretty pictures. In the section titled Assigning IDs to Dynamically Created Controls, I read these magical and most joyful words:

If you view the source HTML before you click the not-working button and after you have clicked it, you will notice a small difference. The buttons have different HTML IDs before and after the post-back. I got ctl04 and ctl05 before the post-back and ctl02 and ctl03 after the post-back.

ASP.NET button recognizes events by checking for a value for its ID in the Request.Form collection. (In truth it happens differently and controls do not check Request.Form collection by themselves. Page passes post data to controls by their IDs and to controls that are registered to be notified about post data). ASP.NET does not fire the Click event, because the button's ID has changed between the post-backs. The button you have clicked and the button you see after are different buttons for ASP.NET.

Sure enough, when I viewed the HTML the first time, my button had the ID ctl04$ctl36. After clicking the button, my button had the ID ctl04$ctl33.

So there you have it! All I had to do was set the ID on the buttons and presto! My event handlers are now being called!

Sample Solution:

public override Control GetAdministrationInterface()
{
    // more code...

    Button btn = new Button();
    btn.Text = "Click Me!";
    // !!THE BANE OF MY EXISTENCE!!
    btn.ID = "The_Bane_of_My_Existence";
    // !!THE BANE OF MY EXISTENCE!!
    btn.Click += new EventHandler(Btn_Click);

    // more code...
}

What a great way to spend two days...

John