Emptied of expectation. Relax. (tinyjo) wrote,
Emptied of expectation. Relax.

  • Mood:

Consuming events from dynamically generated controls in ASP.NET

I'm going to try to describe the process of creating dynamically generated controls and consuming events generated by them. There are bits and bobs about this round the web but the first time I tried it I found it very fiddly because it's very dependant on getting the order of everything right and also because on each page load in my case I needed to have different controls.

The problem: The reason I wanted to be able to do this was that I had a very long questionnaire where the questions were generated from a database that I wanted to split up into sections. What I wanted was for when a user loaded the page initially for them to see

Questionnaire title

Description of Section 1
[Section 1]

Description of Section 2
[Section 2]


Then, when the user clicked on the Section 1 button, the page would re-load and show

Questionnaire title

Description of Section 1
Q1.1 [list of answers]
Q1.2 [list of answers]

Description of Section 2
[Section 2]


Then when they clicked the Section 2 button it would show the section 2 questions and so on. The reason this turns out to be so much more complicated than I expected was that dynamically generated controls get their values back at a different time to other controls - just before the event handling stage.

Solution: The first thing you'll need is a routine, call it DisplayQuestionaire which takes a container (e.g. a panel) and the number of a section and adds the appropriate controls to your panel to display the questionnaire with that section expanded, or when there's no section number (or for section number 0 or whatever) displays the questionnaire with no questions displayed. When you do so, think carefully about what ids you give the buttons, particularly if you don't want to handle the events from all the buttons in the same way (we do in this case but you might not). You'll need to use something like btnSection_1 so that you can easily get the section ID later.

You'll also need a routine, call it ExpandSection, which will handle the clicks of the buttons to expand the sections - I'll explain what this will need to do further down - and a routine, call it SaveSection, to save the results from each section. You can save each bit to a database or I tended to save it to Xml stored in the Session state and wait until the whole thing was done to save it.

The first event we're interested in is the Page_Init event. In here, you want to display the page *as it was the last time it was displayed*. So if it's the first page load (i.e. IsPostBack = false) run your DisplayQuestionaire routine with section number 0. If it's not the first time, then you need to get the sectionID of the section you were displaying previously - I store it in Session state (Session["sectionID"]), you could use ViewState if you like. Call DisplayQuestionaire with the SectionID you get back.

This is also the point you need to add the event handlers. Loop through the controls in your container once they've been added and use AddHandler to set the event handler for all your section buttons to your ExpandSection routine.

Now we can't do anything else until we get to the actual event handler because although we've re-generated our controls they won't get their values back from view state until later.

What happens next is that because of the event handlers we added in Page_Init we will drop into the event handler if the user clicked one of our expand section buttons. The first thing we need to do is save the results of the previous section, which should now have been put back in the controls by the ViewState. Once you've done that, you'll need to find out the button which fired your event, which you can do by examining the ID of the sender of your event. Once you've got the section ID you need to clear out your container and then run DisplayQuestionaire again with the new section ID so that the right bits are displayed to the user.

I know this sounds pretty complicated, but it's not too bad, I'm just a slightly incoherent technical writer. I'll try to stick some code samples up soon and if you have any questions, feel free to comment.
  • Post a new comment


    Comments allowed for friends only

    Anonymous comments are disabled in this journal

    default userpic

    Your reply will be screened