Fog Creek Software
Discussion Board

Welcome! and rules

Joel on Software

Help - Server Control Hierarchy Built Twice

I'm sure this is a design question that is commonly encountered, but I can't find any resources which explain how to solve it. I would deeply appreciate any advice.

Basically, when building a composite server control, I'm trying to avoid having to build the control twice. Here's why this happens:

The routine for building the control can be called from two places: (1) CreateChildControls, or (2) DataBind. If DataBind is called, it sets ChildControlsCreated to false, and creates the controls itself. If it isn't called, then CreateChildControls is automatically invoked, and creates the controls from the ViewState. Great! This works fine.

However, several of the child controls can change the state of the control – essentially, the control has a table, and the table can be rendered in different ways, so you can select different rendering options from the control (horizontal, vertical, etc.) via dropdownlist controls.

When one of these controls is selected, it registers an event, and calls a routine to change some properties of the control that tell it to render differently. However, postback events like this occur after DataBind, and more importantly, after CreateChildControls.

If one of these events is raised, when CreateChildControls is invoked, it doesn't know that the properties of the control are about to change, and therefore the rendering it will perform is about to be obsolete. What happens is that it builds the control hierarchy, then later the event is called, which changes how the control hierarchy should look, and so it MUST REBUILD the control hierarchy again to respond to the changes posted by the event. Therefore, I'm building the control hierarchy twice.

I assume I'm doing something drastically wrong in my design here, but I can't figure out how I should handle this differently. Please, any advice, links, pseudocode, admonishments would be greatly appreciated.

Thanks in advance.

dasein fiasco
Sunday, February 27, 2005

Presuming we're talking about ASP.NEt here... you should create you control hierarchy (and set the default values) in response to the Init event.

Brad Wilson
Monday, February 28, 2005

Thanks for the response. In fact, there are a few ways I could intercept the postback sender, figure out what to change based on its properties, set childcontrolscreated, stored values that would represent the changes to make, and so on.

While this would eliminate the redundancy, it seems like such a hack of a solution that I would rather be stuck with the redundancy than so dramatically depart from the model.

My general feeling now is that the recreation of the control hierarchy is the nature of the beast, and it must be accepted on account of's design. I believe DataGrids and such recreate when an edit index is changed or in responding to other such events that require the control hierarchy to change, so at least I'm no worse than the native framework when I go this route.

Anyway, thanks again for the response.

dasein fiasco
Wednesday, March 2, 2005

"My general feeling now is that the recreation of the control hierarchy is the nature of the beast, and it must be accepted on account of's design."

The nature of the issue is around the auto-assigned control IDs. This is because the auto-assigned control IDs are based on the position of the control within the collection. Insert a control between two others, and everything gets renumbered (and the posted data and events either end up in the wrong place, or simply silently fail).

Generally speaking, there's a few potential solutions.

1. If every control (that has data and/or postback events) had its own hand-assigned control ID, then you don't have the problem. You can insert things anywhere, and the IDs are stuck to the controls rather than auto-assigned. This is often the easiest fix, if it's reasonable (i.e., the page is relatively static and reasonably small).

2. The control tree always contains all the controls you ever want to use, which are selectively hidden using the server-side Visible property (which causes them not to render to the client).

3. If your page is truly dynamic, what you can do is re-create the control tree that was rendered to the client, for the purposes of getting data and events. Then, in response to PreRender, you can stash away some state in Session temporarily, redirect to yourself, find that session data, and render an entirely different control tree.

I've done all three of these techniques at different times. Technique #1 is the most time consuming, but simplest to do. Technique #2 is a little inefficient, and may be difficult to pull off, but has the advantage of not having to hand-ID your controls. Technique #3 is very complex, but extremely powerful and flexible.

Brad Wilson
Wednesday, March 2, 2005

*  Recent Topics

*  Fog Creek Home