Introduction
This article is about imitating the functionality of the Master Pages in the .NET 2.0 framework as close as possible. By doing this, your .NET 1.x site would be able adapt the Master Pages concept once you have converted your site.
Background
I am working on a project which intended to use the .NET 2.0 framework, however early on we received word that the company was not quite ready for the switch. We really wanted to use things like master pages and so on. A quick search for master pages in .NET 1.1 resulted in a hand full of articles but none seemed really easy to use or mimic the functionality of master pages in .NET 2.0.
Using the code
So, I took the approach of taking a masterpage.master from a .NET 2.0 app and used that as the entry point for my solution.
The ContentPlaceHolder controls in .NET 2.0 don�t exist in .NET 1.x so I replaced them with the Panel controls (asp:Panel).
The Master Pages contain the complete HTML layout, in other words everything inthe Master Page is meant to �force� the layout on the calling page while preserving the content of the asp:Panel's (a.k.a ContentPlaceHolder controls) found on the page.
As you can see below, the html layout is what is left over with some default text as the content of the panels. I highlighted the panels so you can compare them with the panels in the calling page which I will discuss a little later.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN" >
<html>
<head>
<title runat="server">Default1</title>
<meta name="GENERATOR" content="Microsoft Visual Studio .NET 7.1">
<meta name="CODE_LANGUAGE" content="C#">
<meta name="vs_defaultClientScript" content="JavaScript">
<link href="Styles/MasterPage_A.css" type="text/css" rel="stylesheet" />
</head>
<body ms_positioning="GridLayout">
<form id="Form1" method="post" runat="server">
<table width="700" cellspacing="0" cellpadding="0" border="0" height="100%" align="center"
id="Table1">
<tr>
<td class="Header" colspan="3">
<asp:Panel ID="pnlHeader" runat="server">
This is MasterPage A, set by the master page.<br />
Place a panel with ID="pnlHeader" in the Default.aspx and this text will be replaced.</asp:Panel>
</td>
</tr>
<tr>
<td class="LeftMenu" valign="top">
<asp:Panel ID="pnlLeftMenu" runat="server">
This text will not show up as it is overridden by the page.
</asp:Panel>
</td>
<td class="Content">
<asp:Panel ID="pnlContent" runat="server">
This text will not show up as it is overridden by the page.
</asp:Panel>
</td>
<td class="RightMenu" valign="bottom">
<asp:Panel ID="pnlRightMenu" runat="server">
This text will not show up as it is overridden by the page.
</asp:Panel>
</td>
</tr>
<tr>
<td class="Footer" colspan="3">
<asp:Panel ID="pnlFooter" runat="server">
Footer area, set by the master page
</asp:Panel>
</td>
</tr>
</table>
</form>
</body>
</html>
As you can see this resembles a possible site layout (simple for this article), with some default text in the Panel's. These Panels will be replaced with the matching Panels found in the calling pages.
I had done other sites where I took HTML pages and used the ParseControl method to turn the html into a Control. Once you have a control, you can go through the controls collection of this control to, well�. find more controls.
I thought that should be possible to use this technique to replace one panel with another.
As I stripped out the content in the Master Page I did the reversed in the calling page (in this case the default.aspx). This means that only the html markup which actually belongs to the page (buttons, labels, panels, user controls and so on) stays while the site layout is safely stored in the master page. Again, mimicking the functionality of the Master Pages in .NET 2.0.
<%@ Page Language="c#" Codebehind="Default.aspx.cs" AutoEventWireup="false" Inherits="Default" %>
<asp:panel id="pnlLeftMenu" runat="server">
This goes in the left menu
</asp:panel>
<asp:panel id="pnlContent" runat="server">
<TABLE>
<TR>
<TD noWrap width="60">
<asp:Button id="Button1" runat="server" Text="Show Time"></asp:Button></TD>
<TD width="100%">
<asp:Label id="Label1" runat="server" Text=""></asp:Label></TD>
</TR>
</TABLE>
</asp:panel>
<asp:panel id="pnlRightMenu" runat="server">
This goes in the Right menu
</asp:panel>
<asp:panel id="Panel1" runat="server">
This panel is ignored and will not be shown on the final page
</asp:panel>
As you can see in the HTML markup above, the site layout is missing, leaving only the Panel's (ContentPlaceHolders) and their content in the page.
Please note the naming of the Panel's in both the Page and the Master Page above. The ID's of the panels can be anything as long as they match between the two pages.
How it works
The solution to merge the Master Page with the calling Page consists of only five (simple) steps:
1) Collect all Panel controls within Page control collection.
2) Delete all the controls on the Page (aspx),
3) Load the Master Page from cache if exist or from disk if not in cache (prevents file locking on high trafic sites),
4) Replace the Panel controls found in the MasterPage with the Panel controls collected in step 2,
5) Add the Updated MasterPage (control) to the Page control (which was cleared in step 2).
Panels defined in the Master Page but not found in the calling page (aspx) will be shown as is, just like in .NET 2.0.
The only thing you need to do in the code behind file of the calling page is add the using System.Web.UI.preMasterPages
directive and derive from the MasterPages
class.
using System;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.UI.preMasterPages;
public class Default : MasterPages
{
private void Page_Load(object sender, System.EventArgs e)
{
Title = "My Page Demo";
}
... The rest of the class is omitted for clarity
}
I added simply a MasterPage element to the web.config with the path and filename of the Master Page to use. You can easily change the code to allow for a "on-the-fly-pick-and-choose" approach.
I simply added a Title
property in the base class wich sets the Title of the page on Page_Load.
You should be able to run your converted page without any code changes, I tried it with dynamically loaded user controls and while persisting state and it all works fine.
Once you are ready to migrate your site, you simply change the asp:Panel
controls to asp:ContentPlaceHolder
in both the aspx and the master page and you are done.
Have fun,
History
- 09-04-2006
- Changed the Code so it has only the Panels in the calling page (aspx) and the complete site layout in the MasterPage.master pages.
Also added a Title property to the base class so the Title of the page can be set on Page_Load.
- 07-04-2006