4.2. Creating a Customizable Navigation Bar

Problem

You want to create a navigation bar that lets you add or remove items without changing code so that you can reuse the navigation bar in multiple applications.

Solution

Create an XML document containing the items that will be displayed in the navigation bar, and then create a user control that uses the contents of the XML document to provide the required customization.

To create the user control:

  1. Create a file with a .ascx extension.

  2. Place the @ Control directive at the top of the file.

  3. Add a DataList control configured to render a table with an ItemTemplate defining the cells in the table.

In the code-behind class for the control, use the .NET language of your choice to:

  1. Create a user control code-behind class that inherits from the UserControl class.

  2. (Optional) Establish properties for the control that will provide the ability to programmatically control the basic look of the navigation bar, such as its background color.

To use the user control in an ASP.NET page:

  1. Register the control by using the @ Register directive at the top of the page.

  2. Place the tag for the user control in the HTML where you want the control rendered.

The output of a test page demonstrating a typical navigation bar user control is shown in Figure 4-2. Example 4-7 shows the XML document we created to define the contents of the navigation bar. Example 4-8 shows the .ascx file for the user control. Example 4-9 and Example 4-10 show the VB and C# code-behind files for the user control. Example 4-11 shows the .aspx file for the test page that uses the user control. Example 4-12 and Example 4-13 show the VB and C# code-behind files for the test page.

Customizable navigation bar output

Figure 4-2. Customizable navigation bar output

Discussion

The general strategy for this solution is to create an XML document that defines the contents of the navigation bar user control. You then use the Page_Load method of the user control’s code-behind to read into a DataSet the XML document containing the navigation bar data and then bind the dataset to a DataList control. The use of a DataSet and DataList control may sound a little unconventional in this application, but it has these distinct advantages:

  • You are not limited to the number of items in the navigation bar.

  • Loading the XML document used to define the navigation bar items into a DataSet makes for easy traversal of those items.

  • A DataList control configured to render a table with an ItemTemplate provides the flexibility in the display of the columns that is needed for customizing a navigation bar.

The example we have written to implement this solution creates a navigation bar user control whose contents are defined by an XML document. But the example goes a bit further in that it provides the ability to define what buttons appear in the navigation bar as well as the ability to customize the color of the bar, change the name of the XML file used to define the bar, and set other properties.

The XML document that defines our navigation bar consists of a series of elements named Public, as shown in Example 4-7. This is actually the name of the navigation bar (explained later). Each of the Public elements contains three elements: the ButtonLink element defines the URL for the navigation bar button, the ImageSrc element defines the image used for the button, and the AltText element sets the text alternative for the image (i.e., the value of the Alt attribute of the IMG tag used for the button).

The .ascx file for our example user control, which is shown in Example 4-8, simply contains a DataList control configured to render a table with an ItemTemplate to define the cells in the table. The ItemTemplate contains an anchor tag used for the navigation and an image tag to display the graphic button.

The code-behind for our example user control, shown in Example 4-9 (VB) and Example 4-10 (C#), contains three properties to enable customization of the navigation bar. The backgroundColor property provides the ability to change the background color of the navigation bar. The xmlFilename property defines the XML document that is used to populate the navigation bar. The navBarName property is used to define the name of the group of elements in the XML document that are used to populate the navigation bar. In this example, all of the elements are named Public. The example’s design allows the XML document to have any number of other element groups, thus providing the ability to have a different navigation bar on different pages depending on the page type, user role, context, or the like. If you wanted a different navigation bar for the private pages in the site, for example, you would add a group of Private elements with the information needed to define the private navigation bar. How to select one is described later.

Our approach advocates leveraging a DataList tabular control for the workings of the navigation bar. Here’s how we populate the DataList:

  1. In the Page_Load method of the code-behind, the XML document containing the navigation bar data is read into a DataSet and then bound to the DataList.

  2. The dlNavBar_ItemDataBound method is then called by ASP.NET for each of the items defined in the XML document (rows in the DataSet). Its job is to set the HRef of the anchor tag and then set the image source and alt text for the image tag.

To use the navigation bar user control in an .aspx page, the control must be registered with the @ Register directive at the top of the page and then the navigation bar control can be inserted into your page. Example 4-11 shows how this is done in our application, including the use of TagPrefix, TagName, and Src attributes that are set to the namespace of the project, the name of the control, and the name (and virtual path) of the .ascx file of the user control, respectively (see Recipe 4.1 for more details on these attributes).

In our example, the three properties of the navigation bar control must also be set. It is possible to set these in the .aspx file; however, because the xmlFilename property must be set to a fully qualified XML filename, this is better done in the code-behind, as shown in Example 4-12 (VB) and Example 4-13 (C#).

The navigation bar user control presented here is somewhat bland compared to most others. For instance, many navigation bars we have implemented support a changing image to indicate the active location in the site, complete with mouse-overs for each new image. When implementing this capability yourself, consider adding additional image information in the XML document to support the “on,” “off,” and “over” images. The typical mouse-over code will need to be added to the .ascx file, and the code-behind will need a currentPage property to provide the ability for it to change the images displayed as a function of the currently displayed page.

Tip

The performance of the navigation control shown in this recipe can be significantly improved by caching the control, as described in Recipe 13.5.

See Also

Recipe 13.5 for caching user controls

Example 4-7. XML used for customizable navigation bar

<?xml version="1.0" encoding="utf-8"?>
<NavBar>
  <Public>
    <ButtonLink>../ChapterMenu.aspx</ButtonLink>
    <ImageSrc>images/nav/button_nav_home_off.gif</ImageSrc>
    <AltText>Home</AltText>
  </Public>
  <Public>
    <ButtonLink>../ProblemMenu.aspx?Chapter=1</ButtonLink>
    <ImageSrc>images/nav/button_nav_datagrids_off.gif</ImageSrc>
    <AltText>Datagrids</AltText>
  </Public>
  <Public>
    <ButtonLink>../ProblemMenu.aspx?Chapter=2</ButtonLink>
    <ImageSrc>images/nav/button_nav_validation_off.gif</ImageSrc>
    <AltText>Validation</AltText>
  </Public>
  <Public>
    <ButtonLink>../ProblemMenu.aspx?Chapter=3</ButtonLink>
    <ImageSrc>images/nav/button_nav_forms_off.gif</ImageSrc>
    <AltText>Forms</AltText>
  </Public>
  <Public>
    <ButtonLink>../ProblemMenu.aspx?Chapter=4</ButtonLink>
    <ImageSrc>images/nav/button_nav_user_controls_off.gif</ImageSrc>
    <AltText>User Controls</AltText>
  </Public>
</NavBar>

Example 4-8. Customizable navigation bar (.ascx)

<%@ Control Language="vb" AutoEventWireup="false" 
            Codebehind="CH04UserControlNavBarVB1.ascx.vb" 
            Inherits="ASPNetCookbook.VBExamples.CH04UserControlNavBarVB1" %>
<asp:datalist id="dlNavBar" runat="server"
                                borderwidth="0" cellpadding="0" cellspacing="0" height="29"
                                repeatdirection="Horizontal" repeatlayout="Table"
                                width="100%">
                    <itemtemplate>
                      <td height="25" align="center">
                        <a id="anNavBarLink" runat="server" >
                        <img id="imgNavBarImage" runat="server" border="0"/></a></td>
                    </itemtemplate>
                  </asp:datalist>

Example 4-9. Customizable navigation bar code-behind (.vb)

Option Explicit On 
Option Strict On
'-----------------------------------------------------------------------------
'
'   Module Name: CH04UserControlNavBarVB1.ascx.vb
'
'   Description: This module provides the code behind for
'                CH04UserControlNavBarVB1.ascx
'
'*****************************************************************************
Imports System
Imports System.Data
Imports System.Web.UI.HtmlControls
Imports System.Web.UI.WebControls

Namespace ASPNetCookbook.VBExamples
  Public MustInherit Class CH04UserControlNavBarVB1
    Inherits System.Web.UI.UserControl

    'controls on the user control
    Protected WithEvents dlNavBar As System.Web.UI.WebControls.DataList

    'private attributes
    Private mXMLFilename As String
    Private mNavBarName As String

    'The following constants define the elements available 
    'in the navigation bar XML document
    Private Const MENU_ITEM_BUTTON_LINK As String = "ButtonLink"
    Private Const MENU_ITEM_IMAGE_SRC As String = "ImageSrc"
    Private Const MENU_ITEM_ALT_TEXT As String = "AltText"

    '*************************************************************************
    '
    '   ROUTINE: backgroundColor
    '
    '   DESCRIPTION: This property provides the ability get/set the 
    '                background color used for the navigation bar
    '-------------------------------------------------------------------------
    Public Property backgroundColor( ) As System.Drawing.Color
                        Get
                          Return (dlNavBar.BackColor)
                        End Get

                        Set(ByVal Value As System.Drawing.Color)
                          dlNavBar.BackColor = Value
                        End Set
                      End Property  'backgroundColor

    '*************************************************************************
    '
    '   ROUTINE: xmlFilename
    '
    '   DESCRIPTION: This property provides the ability get/set the 
    '                name of the xml file used to define the navigation bar
    '-------------------------------------------------------------------------
    Public Property xmlFilename( ) As String
                        Get
                          Return (mXMLFilename)
                        End Get

                        Set(ByVal Value As String)
                          mXMLFilename = Value
                        End Set
                      End Property  'xmlFilename

    '*************************************************************************
    '
    '   ROUTINE: navBarName
    '
    '   DESCRIPTION: This property provides the ability get/set the 
    '                name of the navigation bar definition in the xml file
    '-------------------------------------------------------------------------
    Public Property navBarName( ) As String
                        Get
                          Return (mNavBarName)
                        End Get
                        Set(ByVal Value As String)
                          mNavBarName = Value
                        End Set
                      End Property  'navBarName

    '*************************************************************************
    '
    '   ROUTINE: Page_Load
    '
    '   DESCRIPTION: This routine provides the event handler for the page load
    '                event.  It is responsible for initializing the controls 
    '                on the page.
    '-------------------------------------------------------------------------
    Private Sub Page_Load(ByVal sender As System.Object, _
                          ByVal e As System.EventArgs) _
            Handles MyBase.Load
      Dim dsNavBarData As DataSet

      'load the XML document used to define the navigation bar items
                        'into a dataset to provide easy traversal
                        dsNavBarData = New DataSet
                        dsNavBarData.ReadXml(xmlFilename)

                        'bind the nav bar data to the repeater on the control
                        dlNavBar.DataSource = dsNavBarData.Tables(navBarName)
                        dlNavBar.DataBind( )
    End Sub  'Page_Load

    '*************************************************************************
    '
    '   ROUTINE: dlNavBar_ItemDataBound
    '
    '   DESCRIPTION: This routine provides the event handler for the item
    '                data bound event of the datalist control in the nav bar.
    '                It is responsible for setting the anchor and image
    '                attributes for the item being bound.
    '-------------------------------------------------------------------------
    Private Sub dlNavBar_ItemDataBound(ByVal sender As Object, _
                              ByVal e As System.Web.UI.WebControls.DataListItemEventArgs) _
                              Handles dlNavBar.ItemDataBound
                        'the following constants define the names of the controls in the datalist
                        Const ANCHOR_CONTROL As String = "anNavBarLink"
                        Const IMAGE_CONTROL As String = "imgNavBarImage"

                        Dim anchorControl As HtmlAnchor
                        Dim imageControl As HtmlImage
                        Dim dRow As DataRowView

                        'make sure this is an item or alternating item in the repeater
                        If ((e.Item.ItemType = ListItemType.Item) Or _
                            (e.Item.ItemType = ListItemType.AlternatingItem)) Then
                          'get the data being bound
                          dRow = CType(e.Item.DataItem, _
                                       DataRowView)

                          'find the link control then set it to the url
                          anchorControl = CType(e.Item.FindControl(ANCHOR_CONTROL), _
                                                HtmlAnchor)
                          anchorControl.HRef = CStr(dRow.Item(MENU_ITEM_BUTTON_LINK))
                          'find the image control then set the image source and alt text
                          imageControl = CType(e.Item.FindControl(IMAGE_CONTROL), _
                                               HtmlImage)
                          imageControl.Src = CStr(dRow.Item(MENU_ITEM_IMAGE_SRC))
                          imageControl.Alt = CStr(dRow.Item(MENU_ITEM_ALT_TEXT))
                        End If
                      End Sub  'repNavBarCell_ItemDataBound
  End Class  'CH04UserControlNavBarVB1
End Namespace

Example 4-10. Customizable navigation bar code-behind (.cs)

//----------------------------------------------------------------------------
//
//   Module Name: CH04UserControlNavBarCS1.ascx.cs
//
//   Description: This module provides the code behind for
//                CH04UserControlNavBarCS1.ascx
//
//****************************************************************************
namespace ASPNetCookbook.CSExamples
{
  using System;
  using System.Data;
  using System.Drawing;
  using System.Web;
  using System.Web.UI.WebControls;
  using System.Web.UI.HtmlControls;

  public class CH04UserControlNavBarCS1 : System.Web.UI.UserControl
  {
    // controls on the user control
    protected System.Web.UI.WebControls.DataList dlNavBar;

    // private attributes
    private String mXMLFilename;
    private String mNavBarName;

    // The following constants define the elements available 
    // in the navigation bar XML document
    private const String MENU_ITEM_BUTTON_LINK  = "ButtonLink";
    private const String MENU_ITEM_IMAGE_SRC  = "ImageSrc";
    private const String MENU_ITEM_ALT_TEXT = "AltText";

    //************************************************************************
    //
    //   ROUTINE: backgroundColor
    //
    //   DESCRIPTION: This property provides the ability get/set the
    //                background color used for the navigation bar
    //------------------------------------------------------------------------
    public System.Drawing.Color backgroundColor
                      {
                        get
                        {
                          return(dlNavBar.BackColor); 
                        }
                        set
                        {
                          dlNavBar.BackColor = value;
                        }
                      }  // backgroundColor

    //************************************************************************
    //
    //   ROUTINE: xmlFilename
    //
    //   DESCRIPTION: This property provides the ability get/set the
    //                name of the xml file used to define the navigation bar
    //------------------------------------------------------------------------
    public String xmlFilename
                      {
                        get
                        {
                          return(mXMLFilename); 
                        }
                        set
                        {
                          mXMLFilename = value;
                        }
                      }  // xmlFilename

    //************************************************************************
    //
    //   ROUTINE: navBarName
    //
    //   DESCRIPTION: This property provides the ability get/set the
    //                name of the navigation bar defintion in the xml file
    //------------------------------------------------------------------------
    public String navBarName
                      {
                        get
                        {
                          return(mNavBarName); 
                        }
                        set
                        {
                          mNavBarName = value;
                        }
                      }  // navBarName

    //************************************************************************
    //
    //   ROUTINE: Page_Load
    //
    //   DESCRIPTION: This routine provides the event handler for the page 
    //                load event.  It is responsible for initializing the 
    //                controls on the user control.
    //------------------------------------------------------------------------
    private void Page_Load(object sender, System.EventArgs e)
    {
      // wire the item data bound event
      this.dlNavBar.ItemDataBound +=
        new DataListItemEventHandler(this.dlNavBar_ItemDataBound);

      // load the XML document used to define the navigation bar items
                        // into a dataset to provide easy traversal
                        DataSet dsNavBarData = new DataSet( );
                        dsNavBarData.ReadXml(xmlFilename);

                        // bind the nav bar data to the repeater on the control
                        dlNavBar.DataSource = dsNavBarData.Tables[navBarName];
                        dlNavBar.DataBind( );
    }  // Page_Load

    //************************************************************************
    //
    //   ROUTINE: dlNavBar_ItemDataBound
    //
    //   DESCRIPTION: This routine provides the event handler for the item
    //                data bound event of the datalist control in the nav bar.
    //                It is responsible for setting the anchor and image
    //                attributes for the item being bound.
    //------------------------------------------------------------------------
    private void dlNavBar_ItemDataBound(Object sender,
                                            System.Web.UI.WebControls.DataListItemEventArgs e)
                      {
                        // the following constants define the names of the controls in 
                        // the datalist
                        const String ANCHOR_CONTROL = "anNavBarLink";
                        const String IMAGE_CONTROL = "imgNavBarImage";

                        HtmlAnchor anchorControl = null;
                        HtmlImage imageControl = null;
                        DataRowView dRow = null;

                        // make sure this is an item or alternating item in the repeater
                        if ((e.Item.ItemType == ListItemType.Item) ||
                            (e.Item.ItemType == ListItemType.AlternatingItem))
                        {
                          // get the data being bound
                          dRow = (DataRowView)(e.Item.DataItem);

                          // find the link control then set it to the url
                          anchorControl = (HtmlAnchor)(e.Item.FindControl(ANCHOR_CONTROL));
                          anchorControl.HRef = (String)(dRow[MENU_ITEM_BUTTON_LINK]);

                          // find the image control then set the image source and alt text
                          imageControl = (HtmlImage)(e.Item.FindControl(IMAGE_CONTROL));
                          imageControl.Src = (String)(dRow[MENU_ITEM_IMAGE_SRC]);
                          imageControl.Alt = (String)(dRow[MENU_ITEM_ALT_TEXT]);
                        }
                      }  // repNavBarCell_ItemDataBound
  }  // CH04UserControlNavBarCS1
}

Example 4-11. Using the navigation bar (.aspx)

<%@ Page Language="vb" AutoEventWireup="false"
         Codebehind="CH04DisplayNavBarVB1.aspx.vb" 
         Inherits="ASPNetCookbook.VBExamples.CH04DisplayNavBarVB1" %>
<%@ Register TagPrefix="ASPCookbook" TagName="NavBar" 
                               Src="CH04UserControlNavBarVB1.ascx" %>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
  <head>
    <title>User Control Display Navigation Bar</title>
    <link rel="stylesheet" href="css/ASPNetCookbook.css">
  </head>
  <body>
    <form id="frmNavBarTest" method="post" runat="server">
      <table width="100%" cellpadding="0" cellspacing="0" border="0">
        <tr>
          <td align="center">
            <img src="images/ASPNETCookbookHeading_blue.gif">
          </td>
        </tr>
        <tr>
          <td class="dividerLine">
            <img src="images/spacer.gif" height="6" border="0"></td>
        </tr>
      </table>
      <table width="100%" align="center" border="0" 
             cellpadding="0" cellspacing="0" >
        <tr>
          <td><ASPCookbook:NavBar id="navBar" runat="server" />
          </td>
        </tr>
      </table>
    </form>
  </body>
</html>

Example 4-12. Using the navigation bar code-behind (.vb)

Option Explicit On 
Option Strict On
'-----------------------------------------------------------------------------
'
'   Module Name: CH04DisplayNavBarVB1.aspx.vb
'
'   Description: This module provides the code behind for
'                CH04DisplayNavBarVB1.aspx
'
'*****************************************************************************
Imports System.Drawing

Namespace ASPNetCookbook.VBExamples
  Public Class CH04DisplayNavBarVB1
    Inherits System.Web.UI.Page

    'controls on page
    Protected navBar As ASPNetCookbook.VBExamples.CH04UserControlNavBarVB1

    '*************************************************************************
    '
    '   ROUTINE: Page_Load
    '
    '   DESCRIPTION: This routine provides the event handler for the page load
    '                event.  It is responsible for initializing the controls 
    '                on the page.
    '-------------------------------------------------------------------------
    Private Sub Page_Load(ByVal sender As System.Object, _
                          ByVal e As System.EventArgs) Handles MyBase.Load
      navBar.xmlFilename = Server.MapPath("xml") & "\NavigationBar.xml"
                        navBar.navBarName = "Public"
                        navBar.backgroundColor = ColorTranslator.FromHtml("#6B0808")
    End Sub  'Page_Load
  End Class  'CH04DisplayNavBarVB1
End Namespace

Example 4-13. Using the navigation bar code-behind (.cs)

//----------------------------------------------------------------------------
//
//   Module Name: CH04DisplayNavBarCS1.ascx.cs
//
//   Description: This module provides the code behind for
//                CH04DisplayNavBarCS1.ascx
//
//****************************************************************************
using System;
using System.Drawing;

namespace ASPNetCookbook.CSExamples
{
  public class CH04DisplayNavBarCS1 : System.Web.UI.Page
  {
    // controls on form
    protected ASPNetCookbook.CSExamples.CH04UserControlNavBarCS1 navBar;

    //************************************************************************
    //
    //   ROUTINE: Page_Load
    //
    //   DESCRIPTION: This routine provides the event handler for the page 
    //                load event.  It is responsible for initializing the 
    //                controls on the page.
    //
    //------------------------------------------------------------------------
    private void Page_Load(object sender, System.EventArgs e)
    {
      navBar.xmlFilename = Server.MapPath("xml") + "\\NavigationBar.xml";
                        navBar.navBarName = "Public";
                        navBar.backgroundColor = ColorTranslator.FromHtml("#6B0808");
    }  // Page_Load
  }  // CH04DisplayNavBarCS1
}

Get ASP.NET Cookbook now with the O’Reilly learning platform.

O’Reilly members experience books, live events, courses curated by job role, and more from O’Reilly and nearly 200 top publishers.