4.2.1 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. 4.2.2 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: -
Create a file with a .ascx extension. -
Place the @ Control directive at the top of the file. -
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: -
Create a user control code-behind class that inherits from the UserControl class. -
(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: -
Register the control by using the @ Register directive at the top of the page. -
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. Figure 4-2. Customizable navigation bar output 4.2.3 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 : -
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 . -
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. | The performance of the navigation control shown in this recipe can be significantly improved by caching the control, as described in Recipe 13.5. | | 4.2.4 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 } |