Structuring an ASP.NET 2.0 Site using Master Pages and Navigation Controls

Nov 27, 11:00 pm

Article Author: Chris Hart
.NET 3.5 Books

Introduction


When designing a website, you may find yourself approaching the design from two perspectives. On the one hand, you might spend many hours considering how the site should fit together architecturally, considering which classes you’ll need, how and where to store important application logic, and debating how much logic to push into stored procedures and how much to keep in business components. After spending so much time looking at code, it’s great to get a design together and consider how your application will actually look and feel to an end user. If you just want to get some quick ‘n dirty results into a prototype, or if you’re actually designing the site itself, you’ll almost instantly appreciate the benefits of some new tools available to ASP.NET developers – including master pages and site navigation controls.


Creating a website is a process that always seems to involve a certain amount of repetition. If I want to build a site that has standard headers and navigation bars in ASP.NET 1.x, I tend to build a couple of user controls, reuse them on each page, then copy and paste over a certain amount of layout html to build a structure for each page. There are better ways of doing this (see the related links for this article for details), but they can be a bit tricky for the less experienced, and my job is often to build something that a customer can maintain. I’d rather do away with the repetitive copy and paste, so I’m really glad that ASP.NET 2.0 has the concept of Master Pages that will help with the layout, and some great navigation controls that will save you spending hours of development time on those standard features of your site.


Overview of the New Site Design Features


Before delving into the code, let’s have a quick overview of the main technologies that I’ll be covering in this article series.


Master Pages


The master page is a single central location, a bit like a basic empty "copy and paste" template page. You can use standard elements to lay out the blocks in a page, apply a standard style or theme, and include navigation features, all in this central page. When you develop pages based on a specific master page, you can only add content to editable areas or regions, which are defined in the master. This ensures that your site has a consistent look and feel, so in a way, you could consider this to be a variation of VFI (Visual Forms Inheritance) for the web.


You will also find that the fantastic designer support included in Visual Studio 2005 for creating master and content pages is a real bonus, making it really simple to put together your applications. In ASP.NET 2.0, once you have a master page for a site, adding content pages (pages that are based on the master) is quick and simple. Now all you need do is add content to be displayed in the specified areas of the page, and hey presto – a page appears. The first part of this article looks at how this works.


Navigation Controls


The next innovation I want to show you is the extremely cool navigation controls that have been introduced. In .NET 1.1, you may have found yourself hard-coding links into a navigation user control, or possibly databinding a repeater-style control with hyperlink elements to a central repository for displaying links to the pages on your site. You may even have decided to buy a third party component to help with navigating the content on your site. Well, now there are a couple of great controls that you can use to add some nifty navigation to your site with a minimum of fuss. All you need to do to implement these controls is stick together a bunch of links into an XML file and these controls will be able to bind to this data and display it either as a hierarchical tree of links to each page, or as a breadcrumb trail. Even better: adding these controls to a simple master page means that every content page on your website has access to the central navigation controls – you can click from page to page without having to amend any of the content pages. In the latter half of this article, I’ll show you how to do this, and how to customise what those navigation controls display.


Themes and Skins


In the second article in this series, I’ll show you how to style your sites using ASP.NET’s new styling abilities; notably the introduction of Themes to apply standard HTML styles and CSS stylesheets consistently to server controls, making it far simpler to control and define the look and feel of a site. The aim of themes is to make it possible to control the rendered appearance of a page, having designed it at the server control level.


System Requirements


To run the code in this article, you’ll need the following:


  • Windows 2000, XP (any version), or .NET Server 2003

  • A copy of Visual Web Developer 2005 (or full Visual Studio 2005).

  • A machine (real or virtual) with at least 300Mb of RAM (512Mb or more is great) if you want the design-time experience to be smooth and usable!

Installing and Compiling the Sample Code


The sample code for this article demonstrates using master pages and navigation controls together in a small prototype web application. To install the application, all you need to do is extract the contents of the zip file into a folder on your development box. Open up Visual Studio .NET 2005 and select File | Open | Web Site… from the main menu. Enter the path to the MediaLibrary folder in the dialog and open it – the site can then be run by selecting an ASPX page from the Solution Explorer and hitting the run command on the main toolbar. This will launch the application using the local-only Visual Studio .NET web server so you can test it out without having to create a virtual directory in IIS.


Mastering the Layout of a Site


A master page is used to present a consistent interface for laying out content elements. It can contain HTML markup and server controls like any ASP.NET page, but it also contains one or more ContentPlaceHolder controls. These controls are containers, the contents of which are provided in any content page that is based on that master page. A master page has the extension, .master .


The following code is typical of what a master page contains (this file is called MasterPage_Skeleton.master in the code download):



<%@ Master Language="VB" CodeFile="MasterPage_Skeleton.master.vb" 
  Inherits="MasterPage" %>
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server"> <title id="PageTitle" runat="server">Media Library Master</title>
</head>
<body> <form id="Form1" runat="server"> <div class="header"> <div class="corner"> <img src="Images/media.gif" alt="CDs and DVDs" /> </div> <div class="PageHead"> <asp:Label runat="server" ID="HeaderText" SkinID="HeaderText" Text="Welcome to the site!" /> </div> </div> <table> <tr> <td style="vertical-align: top;"> <div class="navbar"> Series of links here </div> </td> <td style="vertical-align: top;"> <div class="content"> <asp:ContentPlaceHolder ID="PageBodyPlaceHolder" runat="server"> </asp:ContentPlaceHolder> </div> </td> </tr> </table> <div style="text-align: right"> Breadcrumb links here </div> </form>
</body>
</html>


Ok, so that’s the code, but the fun really begins in the Visual Studio .NET environment – let’s look at the designer’s view of the page:



Figure 1.
This figure has been reduced in size to fit in the text. To view the full image Click here


In the center of the screen you’ll notice the ContentPlaceHolder control that defines where content pages based on this master can add their custom content.


Now flip back to Source view  notice that, in among the familiar HTML code is the following line of code:



<asp:contentplaceholder id="PageBodyPlaceHolder" runat="server">
</asp:contentplaceholder>


This control is a container control that can be overridden in a content page visually derived from this master. This means that a content page can add content to this area of the page, but not to any other parts of the page. The ContentPlaceHolder control’s ID attribute is crucial when it comes to creating a content page based on this master.


Now, you don’t have to type all this code in – if you wanted to, you could work in the designer, dragging and dropping elements onto the page to achieve the look you’re after. The ContentPlaceHolder control is just one control you can drag onto a page from the Standard tab in the Toolbox. Just make sure you specify an ID attribute for this control before you create a content page. In this example, the ID has been set to PageBodyPlaceHolder .


Let’s look at a sample content page now. This page is actually just a normal .aspx page, but with less code than you’ll be used to seeing. The following page is a content page called ContentPage.aspx in the code download:



<%@ Page Language="VB" MasterPageFile="~/MasterPage_Skeleton.master" 
      AutoEventWireup="false" CodeFile="ContentPage.aspx.vb" 
      Inherits="ContentPage" title="Content Page" %>
<asp:Content ID="Body" ContentPlaceHolderID="PageBodyPlaceHolder" Runat="Server">
This is the body of the first content page!
</asp:Content>


Notice how the asp:Content element contains a corresponding ID to the placeholder defined in the master page. Again, you’ll find that working within the Visual Studio .NET environment for creating content pages is really great – most of this code was automatically generated simply by creating a new content page and specifying that it uses the MasterPage master. The line of text inside the content area can easily be added while working in the designer  speaking of which, let’s take a look at how this page is displayed in the Visual Studio designer:



Figure 2. Displaying a content page in the VS designer
This figure has been reduced in size to fit in the text. To view the full image Click here


Notice how the placeholder contains content specific to this page, and notice that I can’t edit the contents of the rest of the page because these areas are hidden away in the master page. As you click on an editable area in the designer, you are offered the choice of adding custom content, or adding default content, as defined in the master page. For example, you could add a placeholder to the bottom of a master page to hold footer details, then add some default content for this region. When you create content pages based on that master, you would then have the option of accepting the default content in that area, or customizing it in each content page as appropriate.


Running this simple page will produce the result shown in Figure 3.



Figure 3. A simple content page
This figure has been reduced in size to fit in the text. To view the full image Click here


It’s a simple page, but the only addition made to this page was to add a single line of text. Everything else came from the master. Notice that the site has had some styling applied  this is all due to the inclusion of some ASP.NET Themes with the source code for the site. These will be discussed in the second article of this series.


Working with Master Pages


One way to change the content of different parts of the rendered page is to add more content regions to the master page, but there are alternatives available. For example, say you wanted to change the main welcome message on this site  one solution would be to include a header content region, but the other option is that you can add a public property to the master page, which you can use programmatically to alter the content of the welcome message. You can then access this property from any ASPX page that is based on this master page. The listing below is from the code beside file for the master page, Masterpage_Skeleton.master.vb :



Partial Class MasterPage_Skeleton
    Inherits System.Web.UI.MasterPage


  Public Property HeaderMessage() As String
    Get
      Return HeaderText.Text
    End Get
    Set(ByVal Value As String)
      HeaderText.Text = Value
    End Set
  End Property


End Class


Back in the HTML Source view for the master page, the following line of code contains the standard welcome message for the site:



<div class="PageHead">


  <asp:Label runat="server" ID="HeaderText" SkinID="HeaderText" 
     Text="Welcome to the site!" />


</div>


Now you can edit the text that is displayed on the header area of the ASPX content page by adding a Page_Load event handler to ContentPage.aspx.vb with the following code:



Partial Class ContentPage
  Inherits System.Web.UI.Page


  Private Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) _
    Handles Me.Load
      Master.HeaderMessage = "Welcome: Content Page"
  End Sub


End Class


This change ensures that you now have control over the text rendered in the title of the page:



Figure 4. Changing the header text
This figure has been reduced in size to fit in the text. To view the full image Click here


How Master Pages Work


So, you’ve seen how to add placeholders for content and add content to corresponding content tags on a content page. You can add more than one of these placeholder controls to a master page, allowing you for example to add custom header text to every page on a site. You can also easily change the master page that a content page is based on, simply by changing the master attribute of the content page.


Master pages, as I mentioned briefly earlier, are actually a lot like the user control framework that was first introduced in ASP.NET 1.0. The master page acts like a user control, and contains other controls that define editable regions on a page. In this way, you can work with events raised by the master page and any accessible properties it contains in a very similar way to working with a user control. A Page_Load event in a content page will therefore always fire before the Page_Load in the master page.


You can also nest master pages, hence you could have one master page to define a header, body, and footer information for a page, then select different master pages for the body of the page to switch between views, for example, a two column layout, three column layout, image plus details view layout, and so on. The only downside to nesting master pages is that you will lose designer support unless you use some clever techniques. Scott Guthrie from Microsoft has written an excellent blog article on this process (http://weblogs.asp.net/scottgu/archive/2005/11/11/430382.aspx), and he also hints that the next release of Visual Studio will rectify this problem.


Another neat feature available is the ability to apply a standard master page to any page on a site by adding the following code to the web.config file:



<system.web>
  <pages master="MasterPage.Master" />
</system.web>


This enables you to create content pages without specifying a master page explicitly on each content page, which would make it much simpler to change the master for an entire site from one central location.


Implementing Master Pages in .NET 1.x


One of the guys on the ASP.NET team, David Ebbo, prototyped a system for creating master pages for ASP.NET 1.0/1.1 sites (the results of which can be downloaded from here: http://www.asp.net/ControlGallery/ControlDetail.aspx?Control=385&tabindex=2). The implementation of master pages in the current release of v2 looks very similar to this original idea.


If you’re desperate to implement this feature in current projects, but your organization isn’t planning to move to .NET 2.0 yet, you should check out some of the articles by Paul Wilson: http://authors.aspalliance.com/PaulWilson/Articles/. Paul does a great job of explaining how David Ebbo’s original design actually works. In addition, Victor Garcia Aprea’s weblog also includes some more theory on the subject: http://weblogs.asp.net/vga/posts/7334.aspx.


Navigating a Site


You’re no doubt familiar with the basic concepts involved in adding links on a page to the various content pages that exist on the site, but in ASP.NET 1.1 it can be a time consuming and error-prone task unless you bind your links to data stored externally. The new navigation controls act in this way by default, making it much easier to present a consistent navigation interface to your users. There are three main controls involved that I’ll look at here, the TreeView , SiteMapPath , and Menu controls.


Navigating a Site using the SiteMapPath Control


This control renders a trail of hyperlinks onto a page, representing the links leading back to the home page relative to the currently active link. For example, if I’m viewing a particular genre of music on my media library site, I could have the following:


Home > CDs > Rock



You need to add two things to the site for this control to work:


  • An instance of the SiteMapPath control on a page and

  • An XML file called web.sitemap

The web.sitemap control contains a hierarchy of links to various pages on a site. You can include any valid url for each node, hence the following example demonstrates using querystring values for some of the links:



<?xml version="1.0" encoding="utf-8" ?>
<siteMap> <siteMapNode title="Home" description="Home" url="default.aspx" > <siteMapNode title="DVDs" description="DVD catalog" url="DVDs.aspx"> <siteMapNode title="Action" description="Action titles" url="DVDs.aspx?Category=Action" /> <siteMapNode title="Comedy" description="Comedy titles" url="DVDs.aspx?Category=Comedy" /> </siteMapNode> <siteMapNode title="CDs" description="CD catalog" url="CDs.aspx"> <siteMapNode title="Rock" description="Rock music" url="CDs.aspx?Genre=Rock" /> <siteMapNode title="Pop" description="Pop music" url="CDs.aspx?Genre=Pop" /> <siteMapNode title="Soundtrack" description="Film soundtracks" url="CDs.aspx?Genre=Soundtrack" /> </siteMapNode> </siteMapNode>
</siteMap>


Once you add a SiteMapPath control to a page, it will automatically look for this file and bind to it. Adding an instance of the control to a page is simple. The following examples are part of MasterPage.master , which builds on the code used in the skeleton master page and adds navigation functionality, enabling the master to work when used as the master page for a whole site. The following listing comes from MasterPage.master :



<td style="vertical-align: top;">
          <div class="content">
            <asp:ContentPlaceHolder ID="PageBodyPlaceHolder" runat="server">
            </asp:ContentPlaceHolder>
          </div>
        </td>
      </tr>
    </table>
    <div style="text-align: right">


      <asp:SiteMapPath ID="NavCrumbs" runat="server">
      </asp:SiteMapPath>


    </div>
  </form>
</body>
</html>


The content page for this new master page is called default.aspx , and is supplied in the code download, and contains very similar code to the content page I saw earlier, but it uses MasterPage.master . This change means that default.aspx looks as shown in Figure 5 when it’s rendered:



Figure 5. Master page with a simple site map
This figure has been reduced in size to fit in the text. To view the full image Click here


Notice the small text in the bottom corner simply stating "Home"  this is the root node in the SiteMap code. Once you can navigate to other pages in the site, this becomes more interesting.


The next stage is to add another type of navigation control, and then I’m going to add a couple of pages that you can link to using that control.


Navigating a Site using a TreeView Control


The second way to add navigation to a site is using the TreeView control. This control, as its name suggests, presents a series of links in the format of a hierarchical tree. If you place a copy of this control onto a part of your master page, you can then automatically use this on every content page based on this master in your site. You’ll never have to worry about messing up the formatting of HTML elements around this area of the screen if you add the control to a master-specific region of the page. With very little effort, a fully-functional navigation control can be created for an entire site, and not just a functional control – this control is very flexible and has a lot of flexibility for custom styling. Note that this control is unrelated to the IE Web Control TreeView control that you may be familiar with.


To use this control, you need three things.


  • An instance of the TreeView control on a page

  • A web.sitemap file

  • A SiteMapDataSource control

You’ve already seen a sitemap file, so let’s take a look at the SiteMapDataSource control. This is a non-visual control that can be added to a page (or a master):



<asp:sitemapdatasource id="SiteMapDataSource1" runat="server" />


By default, this control will use the sitemap file. Note, however, that because this is a data source control, you could plug this into a custom data source to pull data about links from an alternative source.


If you use the standard example, then once the data source has been added, the TreeView can be placed on the page:



<table>
  <tr>
    <td style="vertical-align: top;">
      <div class="navbar">


        <asp:TreeView ID="NavTree" runat="server" 
           DataSourceID="SiteMapDataSource1">
        </asp:TreeView>
        <asp:SiteMapDataSource ID="SiteMapDataSource1" runat="server">
        </asp:SiteMapDataSource>


      </div>
    </td>
    <td style="vertical-align: top;">
      <div class="content">
        <asp:ContentPlaceHolder ID="PageBodyPlaceHolder" runat="server">
        </asp:ContentPlaceHolder>
      </div>
    </td>
  </tr>
</table>


Adding this to the master page will enable you to navigate all of the pages on the site, for example, Figure 6 shows what happens when you view the Rock music category on the CDs page (and notice how the SiteMapPath control looks much more interesting now that you’re three levels down into the site!):



Figure 6. Site navigation with a treeview.
This figure has been reduced in size to fit in the text. To view the full image Click here


Notice that this control has some really neat features:


  • You can customize the amount of indentation used for each level in the control

  • You can change whether you want the user to be able to collapse and expand nodes in the tree, or whether all items are displayed by default

  • You can apply formatting to each part of the control, as hinted in the code for the example shown above (you can define different styles for nodes, leaves, and parents, as well as whether the nodes are expandable/collapsible or fixed, and so on)

So I’ve created a navigation control, and this control has made it possible for you to view the other pages in the site! There are some styles applied to this control, and that’s all thanks to the theme used on the site. I’ll look into how themes work in detail in the next article.


Here’s a quick look at the code used in the CDs.aspx page:



<%@ Page Language="VB" MasterPageFile="~/MasterPage.master" 
   AutoEventWireup="false" CodeFile="CDs.aspx.vb" Inherits="CDs" title="CDs" %>
<asp:Content ID="Content1" ContentPlaceHolderID="PageBodyPlaceHolder" Runat="Server"> This is the CD page. If you selected a category, it will appear below:<br /> <br /> <asp:label id="lblSelectedCategory" runat="server"></asp:label> <br /><br /> <asp:datalist id="itemList" runat="server" datasourceid="MediaData"> <itemtemplate> <asp:hyperlink id="HyperLink1" runat="server" navigateurl=’<%# "Item.aspx?id=" & XPath ("id") %>’ text=’<%# XPath ("title") %>’> </asp:hyperlink> </itemtemplate> </asp:datalist> <asp:xmldatasource id="MediaData" runat="server" datafile="Media.xml" xpath="//cd"> </asp:xmldatasource>
</asp:Content>


I’ve used a bit of XPath to grab CDs of a specific genre (if one is selected) from the Media.xml file (which stores all of the detail for CDs and DVDs available on the site), or to display all CDs if no genre is selected:



Protected Sub Page_Load(ByVal sender As Object, ByVal e As System.EventArgs) 
    Handles Me.Load
  lblSelectedCategory.Text = Request.QueryString("Genre")
  Dim genre As String = Request.QueryString("Genre")
  If Not genre Is Nothing Then
    MediaData.XPath = "//" & genre.ToLower() & "/cd"
  End If
  Page.DataBind()
End Sub


Navigating a Site using a Menu Control


An alternative to the TreeView control is the Menu control. Adding a Menu control to a page is a similar process to adding the TreeView control. In the following example, MasterPage2.master has an asp:Menu control in place of the TreeView control in the navigation section on the left of the page:



<td style="vertical-align:top;">
  <div class="navbar">


    <asp:Menu ID="Menu1" runat="server" DataSourceID="SiteMapDataSource1"> 
    </asp:Menu>


    <asp:sitemapdatasource id="SiteMapDataSource1" runat="server">
    </asp:sitemapdatasource>
  </div>
</td>


The DVDs.aspx page on the site is quite similar to the CDs page, however the DVDs page uses MasterPage2.master as its master page (the only other differences to the DVDs page itself are in the XPath statements used to retrieve the data from the XML file):



Figure 7. The DVD master page from the sample code
This figure has been reduced in size to fit in the text. To view the full image Click here


It’s a little tricky to see this in a static image, but that menu flyout is actually dynamic. The menu control reminds me of toolbars in Word, or the Start menu, whereas the TreeView is like working in Explorer view – each has its merits!


The menu control can be rotated horizontally, if you prefer, to present the links to items on the site as a series of drop-down options. An example of this is shown on the Books page:



Figure 8. The Books master page from the sample code
This figure has been reduced in size to fit in the text. To view the full image Click here


The Books page is based on MasterPage3.Master, which is included in the code download for this article. Notice that no matter which page you are currently viewing, you can click from one page to another and the navigation nodes will still function as the master pages switch. This makes it easy to have slightly different layouts and user experiences for different parts of a site.


Conclusion


Master pages alone are a big draw for migrating to ASP.NET v2. For those who haven’t discovered how to implement them using existing techniques, and even for those who already know how to do this, the integration with the IDE and the ease of use of this feature is a real selling point.


The new navigation controls similarly make putting together a functional solution that bit easier. In a recent ASP.NET 1.1 project, I spent a fair amount of time implementing my own custom navbar control, but I could have saved a lot of time had I been able to use the TreeView control. The Menu control is very similar to use in terms of adding it to the page, and the SiteMapPath control is even simpler. The bit I’ve not discussed in this article is how the behavior of the controls has been configured, since this is controlled by the themes in use on the site. The next article in this series looks at how you can specify both the appearance and user experience of these controls in one central location as I look at Themes in ASP.NET.

Founders at Work

Commenting is closed for this article.