Click here to Skip to main content
16,007,277 members
Articles / Web Development / HTML
Article

MasterPages for .NET 1.1 (again)

Rate me:
Please Sign up or sign in to vote.
4.17/5 (11 votes)
8 Apr 20064 min read 57.1K   440   26   10
Prepare your .NET 1.x site for the use of MasterPages in .NET 2.0

Sample Pages A and B

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.

<P><%@ Page Language="c#" Codebehind="Default.aspx.cs" AutoEventWireup="false" Inherits="Default" %>

</P><P><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></P>

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.

C#
using System;
using System.Web;
using System.Web.UI.WebControls;
using System.Web.UI.HtmlControls;
using System.Web.UI.preMasterPages;

/// <SUMMARY>
/// Summary description for Default.
/// </SUMMARY>
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
    • Initial Release

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
Web Developer
Canada Canada
Wouter is currently working for Fujitsu Consulting [Canada] Inc in Calgary, Alberta, Beautiful Canada.
He has been working with the .NET framework since the early days, so consider him a dinosaur.
If he is not programming you can find him out in the field flying his F3A Pattern plane.

Comments and Discussions

 
GeneralButton question Pin
ICTech26-Jun-07 17:36
ICTech26-Jun-07 17:36 
GeneralRe: Button question Pin
W vanEck26-Jun-07 18:50
W vanEck26-Jun-07 18:50 
GeneralRe: Button question Pin
ICTech27-Jun-07 3:58
ICTech27-Jun-07 3:58 
GeneralRe: Button question Pin
W vanEck27-Jun-07 4:02
W vanEck27-Jun-07 4:02 
GeneralRe: Button question Pin
ICTech27-Jun-07 5:46
ICTech27-Jun-07 5:46 
GeneralRe: Button question Pin
W vanEck27-Jun-07 5:54
W vanEck27-Jun-07 5:54 
Generalerror in content page Pin
veerbala18-Apr-07 2:47
veerbala18-Apr-07 2:47 
GeneralRe: error in content page Pin
W vanEck26-Jun-07 18:49
W vanEck26-Jun-07 18:49 
GeneralSource Code for VB Version [modified] Pin
mazadel30-Jun-06 2:39
mazadel30-Jun-06 2:39 
Hi Everyone, I found this article to be of great help as I needed a class to take away the hassle of HTML from most of my aspx pages when using .NET 1.1. Thanks to Wouter for his help, I have converted the masterpage class from C# to VB. For all of you that are looking for the VB version, you can find it below with the added ability for multiple masterpages. The class will check the SelectedMasterPage variable (which you set from your aspx page page_init which is the key in the web.config that relates to the master page file) upon initialising and if not set will default to the default masterpage i.e MasterHomePage. Enjoy.

Imports System
Imports System.Configuration
Imports System.Web
Imports System.Web.Caching
Imports System.Web.UI
Imports System.Web.UI.WebControls
Imports System.Web.UI.HtmlControls
Imports System.Collections
Imports System.IO

' ====================================================================
' Developed by Wouter van Eck, Flyersoft Inc on April 6th, 2006
' Send your questions to info@flyersoft.net
' Converted from C# to VB, Added ability for multiple masterpages by Mario Delicata 2006

Namespace preMasterPages

'This class takes care of loading the Master Pages, collecting
'the panels (ContentPlaceHolder controls in .NET 2.0),
'and replacing the matched panels in the master page (htm) with the
'panels found in the actual page (aspx).
Public Class MasterPages
Inherits Page

Public SelectedMasterPage As String = Nothing

Protected WriteOnly Property title() As String
Set(ByVal Value As String)
Dim testControl As Control
For Each testControl In Page.Controls(0).Controls
If testControl.GetType.Name = "HtmlGenericControls" Then
If CType(testControl, HtmlGenericControl).TagName.ToLower() = "title" Then
CType(testControl, HtmlGenericControl).InnerText = Value
Exit Property
End If
End If
Next
End Set
End Property

Public Property MasterPage() As String
Get
If SelectedMasterPage = "" Then
If (ConfigurationSettings.AppSettings("MasterHomePage") Is Nothing) Then
Throw New Exception("No Master Home Page Specified")
Else
Return ConfigurationSettings.AppSettings("MasterHomePage")
End If
Else
Return ConfigurationSettings.AppSettings(SelectedMasterPage)
End If
End Get
Set(ByVal Value As String)
SelectedMasterPage = Value
End Set
End Property

#Region "BasePage Code"
Protected Overrides Sub OnInit(ByVal e As EventArgs)

MyBase.OnInit(e)

Dim basePage As String = Me.MasterPage

Dim myPanels As ArrayList = New ArrayList(0)

If Not Request.QueryString("PageID") Is Nothing Then
basePage = Request.QueryString("PageID")
End If

GetPagePanels(myPanels)

' Delete all the controls from the page
Page.Controls.Clear()

' Load the master page
Dim masterPage As String = GetMasterPage(basePage)

'Parse the master page into a control
'If the HTML is wrongly formatted then it will break
Dim myControl As Control = ParseControl(masterPage)

'Apply the panels (ContentControlHolders) to the "MasterPage"
ApplyPanelsToMasterPage(myPanels, myControl)

'Add the newley formed page to the forms control collection
Page.Controls.Add(myControl)

End Sub

'--------------------------------------------------------------------------
'Function GetpagePanels
' The method collects all the Panels on the current Page, these Panels'
' are treated in a similar way as the contentPlaceHolder controls in .NET 2.0
' The Panels are collected from the current page where they are later on
' replacing the identically names panels in the "master page".

Private Sub GetPagePanels(ByRef myPanels As ArrayList)
Dim myObject As Object

For Each myObject In Page.Controls
If myObject.GetType().Name = "Panel" Then
myPanels.Add(CType(myObject, Panel))
End If
Next

' Clear the form controls,
' They are all to be replaced by the master page.
Page.Controls.Clear()
End Sub

'--------------------------------------------------------------------------
'Function GetMasterPage
' Loads the "Master Page", which is a HTML file containing only the html code
' belonging to the body of the FORM

Private Function GetMasterPage(ByVal masterBase) As String
Dim myCache As Cache = HttpContext.Current.Cache
Dim masterPage As String = ""

'Retrieve the masterpage from the cache if available
If Not myCache(masterBase) Is Nothing Then
Return myCache(masterBase).ToString()
Else
'Get the location of the file
Dim myFile As String = Server.MapPath(masterBase)

'Read the HTML from file
Dim myReader As TextReader = New StreamReader(myFile)
masterPage = myReader.ReadToEnd()
myReader.Close()

'Create a dependency of the file
Dim masterPageDependency As New CacheDependency(myFile)

'Add the masterpage to the cache
myCache.Add(masterBase, masterPage, New CacheDependency(myFile), _
Cache.NoAbsoluteExpiration, Cache.NoSlidingExpiration, CacheItemPriority.Normal, Nothing)

Return masterPage
End If
End Function

Private Sub ApplyPanelsToMasterPage(ByVal myPanels As ArrayList, ByRef myControl As Control)
Dim myForm As HtmlForm = Nothing
Dim testControl As Control

For Each testControl In myControl.Controls
If testControl.GetType().Name = "HtmlForm" Then
myForm = CType(testControl, HtmlForm)
Exit For
End If
Next

If Not myForm Is Nothing Then

Dim ControlIndex
Dim random As Object
Dim arrIndex As ArrayList = New ArrayList
For Each random In myForm.Controls

If random.GetType.Name = "Panel" Then

arrIndex.Add(CType(myForm.Controls.IndexOf(random), Integer))

End If

Next

Dim myPanel As Panel = Nothing

For Each myPanel In myPanels
For ControlIndex = 0 To arrIndex.Count - 1

If (myForm.Controls(arrIndex(ControlIndex)).ID.ToString = myPanel.ID.ToString) Then

myForm.Controls.RemoveAt(arrIndex(ControlIndex))
myForm.Controls.AddAt(arrIndex(ControlIndex), myPanel)

End If

Next
Next
Else
Throw New Exception("Form Tag Not Found in Master Page")
End If
End Sub

#End Region

End Class

End Namespace


Mario Delicata - Web Developer
email : mario@furtheronline.co.uk
Website: www.furtheronline.co.uk


-- modified at 18:20 Tuesday 17th October, 2006
QuestionDesigner support? Pin
Mike Lang12-Apr-06 5:49
Mike Lang12-Apr-06 5:49 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.