Posted 2007-02.
ASP.NET 2.0 has a built-in feature that allows you to create a consistent layout for your site, unlike 1.1 where you had to roll your own. (one way to do it on my blog) Read the Master Pages Overview for a background.
Master Page Quickstart
1. Create a master page - call it MASTER.master and place it anywhere in your application directory:
<%@ master language='c#' codefile='MASTER.master.cs' inherits='MASTER' %>
<html>
<head runat='server'>
<title>kuujinbo.info</title>
</head>
<body>
<form id='form1' runat='server'>
<!--
you can have as many contentplaceholder controls
as needed, as long as they are contained within the form
control above
-->
<asp:contentplaceholder id='PLACEHOLDER_NAME' runat='server'>
EMPTY PAGE!
</asp:contentplaceholder>
</form>
</body>
</html>
See strongly typed master pages below for examples of what goes in the code behind file of the master page.
2. Optionally, add the following line to web.config, which will automatically link all .aspx files in your application to the master page:
<pages masterPageFile='/PATH_TO/MASTER.master' />
The pages element is a child element of <system.web>. If you do not want the master page set application-wide, you must instead set the Page directive in each .aspx file:
<%@ page language='c#'
codefile='WHATEVER.cs' inherits='WHATEVER'
masterpagefile='/PATH_TO/MASTER.master'
%>
3. Either way, the final step is to dump all content (ASP.NET controls and text in the .aspx file) in Content control(s) that render the ContentPlaceHolder control(s) created in the master page:
<asp:content id='content_01' contentplaceholderid='PLACEHOLDER_NAME' runat='server'>
<h1>YOUR HEADING</h1>
<p>A paragraph</p>
<asp:datagrid id='DATAGRID' runat='server'>
...
</asp:datagrid>
<asp:label id='LABEL_01' runat='server' />
</asp:content>
Strongly Typed Master Pages
The simplest way to access members of your master page in application pages/.aspx files is to use strong typing. For example, say that you want to change some style properties on certain pages:
1. Create the control in the .master file:
<head runat='server'>
<asp:literal id='YOUR_ID' runat='server' />
...
</head>
2. Expose the property in the .master file's codebehind:
public partial class root : System.Web.UI.MasterPage {
// change the banner image
// add dynamic css/js source files
public string dynamic_css_js {
set { YOUR_ID.Text = value; }
}
// rest of code
}
3. Set the MasterType directive in the .aspx page:
<%@ mastertype virtualpath='/PATH_TO/MASTER.master' %>
4. Set the property in the .aspx file's codebehind; the event handler for the linkbutton (hyperlink) below the following code snippet:
protected void change_style(object sender, CommandEventArgs e) {
Master.dynamic_css_js = Master.dynamic_css_js == String.Empty
? "<link rel='stylesheet' href='/css/test_mp.css' type='text/css' />"
: String.Empty;
}
Dynamic Master Pages
Just before doing this write-up, I added an option for to view pages on this site in text-only format. (removed 2007-02-23) Master Pages makes the task relatively simple:
1. Set up a separate text-only master page.
2. In the default master page, add a linkbutton control.
// somewhere in the (default) master file
<asp:linkbutton id='st' runat='server'
text='Text Version'
causesvalidation='false'
oncommand='swap_template'
/>
The text version master page also needs a linkbutton control as above, except the Text property should be set to something like "Default Page Layout".
3. The event handler in the codebehind file simply writes a cookie that flags when the text template is being requested; in this case the string "True":
// default master page codebehind event handler
protected void swap_template(object sender, CommandEventArgs e) {
HttpCookie c = new HttpCookie("text_template", "True");
// in the text version master page
// HttpCookie c = new HttpCookie("text_template", "");
c.Expires = DateTime.Now.AddYears(1);
Response.Cookies.Add(c);
Response.Redirect(Request.Url.ToString());
}
I can get away with only testing for and setting the text master page, since there's only two templates on this site. However, if more than two different layouts (master pages) were required it would instead be necessary to assign the cookie's value to the path of each different master page.
3. As outlined in the ASP.NET Page Life Cycle Overview, you must set a master page dynamically in System.Web.UI.Page's PreInit event. Assuming you're using some sort of base class that inherits from System.Web.UI.Page, it only takes is a couple of lines of code:
override protected void OnPreInit(EventArgs e) {
bool is_text_master;
// since we're only using two different templates, only
// change the template when the text version is requested
if (Request.Cookies["text_template"] != null &&
Boolean.TryParse(
Request.Cookies["text_template"].Value, out is_text_master
)
)
this.MasterPageFile = "/PATH_TO/text.master";
}