Creating a ControlBuilder for the page itself

One user on my previous post on ProcessGenerateCode asked how he could associate a ControlBuilder not with a control, but with the page itself.  There is in fact a way to do it, and it’s another one of those things that have never really been advertized.  The trick is that instead of associating the ControlBuilder using the standard ControlBuilderAttribute, you need to use a FileLevelControlBuilderAttribute.  Let’s walk through a little example.

First, we create a custom page type with that attribute:

 [FileLevelControlBuilder(typeof(MyPageControlBuilder))]
public class MyPage : Page {
}

We could do all kind of non-default thing in the derived Page, but I’ll keep it simple.  Now let’s write the ControlBuilder for it:

 // Note that it must extend FileLevelPageControlBuilder, not ControlBuilder!
public class MyPageControlBuilder : FileLevelPageControlBuilder {
    public override Type GetChildControlType(string tagName, IDictionary attribs) {
        // If it's a Label, change it into our derived Label
        Type t = base.GetChildControlType(tagName, attribs);
        if (t == typeof(Label)) {
            t = typeof(MyLabel);
        }

        return t;
    }
}

The most important thing to note here is that it extends FileLevelPageControlBuilder, not ControlBuilder.  If you extend ControlBuilder, it may seem like it works on simple pages but some things will break (e.g with master pages).

As for what we do in that class, it’s just some random thing to demonstrate that it is in fact getting called.  Here, we change the type of all Labels to a derived type which slightly modifies the output:

 public class MyLabel : Label {
    public override string Text {
        set { base.Text = "[[" + value + "]]"; }
    }
}

And then of course, we need to tell our aspx page to use our base class:

 <%@ Page Language="C#" Inherits="MyPage" %>

The full runnable sample is attached below.

FileLevelControlBuilder.zip