Open New Window For Code Reference
The next crucial step is to override the Page.Init
method and call the custom initialization procedure, LoadControls
. This is where most of the work gets done, where the control tree is initialized for the page.
I've included a mythical "TopBar" control to illustrate that if you have any standard site navigation, images, etc., you should load them into web user controls (as you probably would even if you weren't using a templating scheme). These controls will be placed in the basic page layout for your site that you create in the LoadControls
method.
So, the first thing I do in the LoadControls
method is load up my TopBar
control. I then assign all of my PlaceHolder
controls' Id
property (on the off chance you need to Find
them by their Id
at some point). Then comes the page layout. I've created a little helper method, AddStaticText
, that I use to add literal controls where static text is needed. (In case you don't know, each contiguous bit of HTML/Text that you put on an ASPX/ASCX page is parsed into a LiteralControl
, so we're just using the same method that ASP.NET does to add text like this to the control tree.)
You'll note that I'm using LiteralControl
controls for the <TITLE /> and stylesheet declarations that use the Title
and StyleSheet
properties for their values. This of course assumes that you'll be using a stylesheet file. If you are not, you can simply remove the code for the StyleSheet
property. The same goes for any of the other default controls on this template--there is no requirement to create all of the same place holders that I have--feel free to change them around all you like.
The next thing I do is add my "Head" PlaceHolder
to the control collection. This of course is there to make it easy to add client-side script functions in what I believe to be the proper place. If you wanted to go all out, you could go ahead and create a "Script" PlaceHolder
that writes out the <SCRIPT /> tags for you.
After opening the body, I go ahead and add my TopBar
control. If I had a more complex layout, such as a left and right bar containing ads, navigation, or what have you, I would likely build the layout here with a table that has the least amount of formatting and content possible here because modifying UI on user controls is easier than modifying UI in code.
Next, I add a "body" DIV with a specific Id
("bodyDiv") so that I can give the "body" specific styles by creating a CSS Id declaration. You could do this with a CSS class as well, depending on preference. Then, to the Body PlaceHolder
, I add all of the parsed controls from the child ASPX. Again, this place holder is arbitrary; I simply used it to expose another place to add controls to programmatically if I, or any user of this template, so desire.
After this, I add the Body PlaceHolder
to the main form. This is a key step; in order for controls in the ASPX to participate in postback and raise corresponding events, they must be part of the server-side form. So you could have skipped adding the parsed controls to the Body PlaceHolder
and added them directly to the form, but as I said, I used the Body PlaceHolder
to enable consumers of the class to know exactly where the parsed controls are added in the control tree and to expose it for them to add more controls via code. The key thing to remember is that for a control to participate in postback and/or raise any of its server-side events, it MUST be part of the server-side form.
Key Note:This brings up an important consideration. Some of the other templating schemes I've seen do not create a server-side form for you. In cases where you're producing mostly static content that does not require server-side, object-oriented postback handling, having a server-side form is largely unnecessary; however, if most of your pages will need postback handling (such as in a web application in the strict sense) and given that ASP.NET limits you to one and only one server-side form, it makes sense to create that one server-side form in your base page class (your template class) so that you do not have to declare it on every page and so that all parts of your page template (such as your various navigation controls and the controls parsed from the ASPX) can participate in object-oriented postback event handling and view state.
Keep in mind that this is not the same thing as placing a server-side form in a user control. Microsoft rightly recommends against that because it limits postback participation to those server controls in your user control. In this template, however, all (or as many as you want) server controls will be added to the server-side form and can thus participate in postback.
Finally, I add a nifty footer including my copyright statement. (This would also be a good place to add a link to a privacy policy.) I add the form to the Page.Controls
collection (a vital but simple step), and I close the BODY and HTML tags for the page.