R – How to change child controls in a composite server control on postback

asp.netcomposite-controlswebforms

I have an ASP.NET web form composite control, let's call it control A, which contains a child composite control, which I'll call control B. The child controls of control B are dependent on a property of control A.

On initial load I am setting this parameter in OnLoad of control A and everything works fine with the control B setting up its child controls correctly in CreateChildControls.

However, when I want to change this parameter via SelectedIndexChanged on a dropdown in control A the event handler seems to be handled too late in the lifecycle for control B to pick up the changed value. Presumably this is because the CreateChildControls method of control B has already been called.

How can I get control B to update its child controls in such a way that they can then go through their normal lifecycle, loading viewstate as necessary?

Just for clarity, when the parameter of control A is changed the child controls of control B may have to have some that remain, some that need to be removed and some that need to be added, hence for the ones that remain they still need to load state.

Best Answer

The SelectedIndexChanged event will be handled after the Page_Load (OnLoad) of the page and control A. And you are right in thinking that your page is already rebuilt and viewstate reinstated back to controls by the time you get to this event handler - as it should be, what is the point of handling events when the page/control has not been rebuilt yet?

The three easy solutions i would suggest for this are:

  • don't have control B check its parent for a value and then build itself accordingly, this is a bit of an anti-pattern. Instead, have control A load the right version of control B depending on the value of the dropdown. IOW make control A responsible for what is loaded, not control B. Control B should be dumb and not care what its parent is. If it needs to interface to its parent it should do it through an interface.

  • if you are only hiding and showing fields, then just have them all in control B, and hide the ones that should not be shown. Most controls will not render any HTML to the output stream if you set their visible property to false, so there is minimal impact on the client side when the page gets sent back to the client

  • have control A rebuild portions of itself depending on the selected value. It could contain a DIV, you do a div.Controls.Clear(), and then add the right controls back in to it. This will be fine to do in the SelectedIndexChanged event, as you don't care what controls are already there and what their values are (if you do care about some of the existing controls, then it is relatively trivial to not clear those from the control collection and to add the new controls around them)

Each of these three methods has it's pros and cons, and what you may end up doing is a mixture of the three. There is also another possible method where you utilise the PageParser and its GetCompiledPageInstance method to get an IHttpHandler that you use to regenerate the page, but that is way to advanced to cover with a small reply here.