Depending hard on being inserted into the control tree

Note: this entry has moved.

This morning while I was waiting for an ASP.NET talk at the MVP Summit I noticed that my weblog was a *bit* outdated… so I decided to blog about one of the 5783 things that I was saving for later.

 

Some controls tend to depend on being added to the control tree in order to work properly before they can be used. For example, it’s common to see code like this in a Control’s Render method:

                                           

base.Page.GetPostBackClientEvent(this, "");

 

this will cause an exception if you use the control in a way like this:

 

MyControl a = new MyControl ();

// MyControl is never inserted into the control tree

// because of this Page property will be null

// MyControl.RenderControl uses Page, bad things will happen

a.RenderControl (writer);   

 

The solution to this is to program the control’s Render method in a more flexible way, that is, considering that the control may not be inserted into the control tree while someone may still want to get its rendering, i.e.:

 

if (base.Page != null)

base.Page.RegisterRequiresPostBack (this);

 

Of course if you’re dealing with a third-party or built-in ASP.NET control you just can’t modify the way the control was coded. So what?

 

Play nice as the CheckBoxList does

 

Insert the control to the control tree just so it gets its properties properly set (Page, ID, etc). This is actually what ASP.NET’s CheckBoxList control does in its public ctor: it instantiates a CheckBox and inserts it into its control tree. It is safe then to call CheckBox.RenderControl because its Page property will be already set, i.e.:

 

MyControl a = new MyControl ();

Controls.Add (a);

a.RenderControl (writer);

 

Or cheat do as the RadioButtonList does

 

UPDATE: I just checked and Control.Page property does has a set accesor, so I believe I may have been confused by the compiler inlining the call to the set accesor.

Instead of adding it to its control tree, RadioButtonList will set the Control.Page property by using code like this:

 

MyControl a = new MyControl ();

a.Page = this.Page

 

Relax a bit, as Whidbey does

                                              

Obviously if its makes sense for some of the functionality of your control to be used even if it’s not inserted into a control tree then by all means you should make that easy for the developers using your control; this means that every time you write code that uses the Page property you should check if it’s non-null.

 

Both CheckBox & RadioButton in v1.x don’t follow this advice. At some point they assume that Page will be always non-null and that’s why any of the previous two detailed solutions will be needed.

 

Luckily Whidbey changes this. The new CheckBox & RadioButton had been modified to relax a bit their dependencies on being inserted into the control tree. They now carefully check Page being a non-null reference before trying to use it.

 

4 Comments

  • > Third-party devs won’t be able to do this. This is not fair!

    Can't you just use:

    a.Page = this.Page;



    But I'm not sure what you're trying to achieve. If your server control is not yet in the control tree, this.Page will be null too.



    Your example of calling RenderControl is a bit artificial. Can you think of any real-world situations where a control won't be in the control tree in the render phase?

  • Real-world examples: the builtin ASP.NET RadioButtonList and any other control that choses a rendering (instead of composition) approach (you can find render vs. composition info on Nikhil's book).



    What I'm trying to say is that when possible your control should be coded in a way that it will also work even if its not into the control tree (ie. rendering).



    Yes, you could do a Control.Page = blah -- I was first confused by the fact that the dissasembled code for RadioButtonList used a stfld instruction to directly set the internal member, which made me believe there was no set accesor for Control.Page property. But I just checked and Control.Page do have a set accesor so I believe that the compiler has just inlined the call to set_Page. Will try to modify the post's text to reflect this.

  • Good Tip for my developments! Thank you.

    And congratulations for your new project, Clarius Consulting. You did not tell us nothing about it!

    Regards from Rosario, Arg.

  • Hi Gabriel,



    Its nice to see someone from Argentina!.

    Re: Clarius -- its true I haven't said much yet, I have Cazzu for that ;-)

    Just checked your site and it looks like you've an impressive set of controls...

Comments have been disabled for this content.