db driven hierarchical menu using asp.net 2.0

8
Building a Database Driven Hierarchical Menu using ASP.NET 2.0 Introduction This tutorial will show you how to store hierarchical menu data in a single database table and how to retrieve and transform that data for display in Microsoft's Menu. Each step is explained and illustrated so that you can quickly extrapolate from this article to build your web application's menu. Note: This tutorial requires Visual Studio 2005 and SQL Server. Step 1 - Create and Fill a Database Self Join Table Our menu's table will use a self-join relationship which is the simplest method of storing hierarchical data. Child rows will use ParentID to establish a relationship with the MenuID of a parent row as shown below. Figure 1 - Table Overview Let us start by creating a database called MenuDb and a Table called Menu. This can be done by running the following script from Microsoft's Query Analyzer. Listing 1 - Database Script CREATE DATABASE MenuDb

Upload: rajchanchal

Post on 10-May-2015

2.399 views

Category:

Technology


6 download

TRANSCRIPT

Page 1: Db Driven Hierarchical Menu Using Asp.Net 2.0

Building a Database Driven Hierarchical Menu using ASP.NET 2.0

Introduction

This tutorial will show you how to store hierarchical menu data in a single database table and how to retrieve and transform that data for display in Microsoft's Menu.

Each step is explained and illustrated so that you can quickly extrapolate from this article to build your web application's menu.

Note: This tutorial requires Visual Studio 2005 and SQL Server.

Step 1 - Create and Fill a Database Self Join Table

Our menu's table will use a self-join relationship which is the simplest method of storing hierarchical data. Child rows will use ParentID to establish a relationship with the MenuID of a parent row as shown below.

Figure 1 - Table Overview

 

Let us start by creating a database called MenuDb and a Table called Menu.  This can be done by running the following script from Microsoft's Query Analyzer.

Listing 1 - Database ScriptCREATE DATABASE MenuDbGOUSE MenuDbGOCREATE TABLE [Menu] (      [MenuID] [int] IDENTITY (1, 1) NOT NULL ,      [Text] [varchar] (50) COLLATESQL_Latin1_General_CP1_CI_AS NULL ,      [Description] [varchar] (255) COLLATESQL_Latin1_General_CP1_CI_AS NULL ,      [ParentID] [int] NULL ,      CONSTRAINT [PK_Menu] PRIMARY KEY CLUSTERED       (            [MenuID]

Page 2: Db Driven Hierarchical Menu Using Asp.Net 2.0

      )  ON [PRIMARY] ) ON [PRIMARY]GOINSERT INTO MENUSelect 'Product','A List of Products', NULLUNION ALL Select 'Applications','Appliations',NULLUNION ALL Select 'Document','Documentation', NULLUNION ALL Select 'Support','Support', NULLUNION ALL Select 'Download','Download', NULLUNION ALL Select 'Background','ProductBackground', 1UNION ALL Select 'Details','Product Details', 1UNION ALL Select 'Mobile Device','Mobile DeviceApplications', 2UNION ALL Select 'Portal','Portal Applications',2UNION ALL Select 'Web Applicaitons','WebApplications', 2UNION ALL Select 'Demo','Demo Applicaitons', 2UNION ALL Select 'Performance Tests','ApplicationPerformance Tests', 2UNION ALL Select 'Tutorials','TutorialDocumentation', 3UNION ALL Select 'Programmers','ProgrammDocumentation', 3UNION ALL Select 'FAQ','Frequently AskedQuestions', 4UNION ALL Select 'Forum','Forum', 4UNION ALL Select 'Contact Us','Contact Us', 4UNION ALL Select 'InternetRestrictions','Internet Restrictions', 6UNION ALL Select 'Speed Solution','Speed Solutions',6UNION ALL Select 'Application Center Test','Application Center Test Results', 12UNION ALL Select 'Modem Results','Modem Results',12GO

The table you created, displayed below, uses self-join relationships.  Rows that have a MenuID between 1 through 5 do not have parents and are considered root menu nodes. Rows with MenuID of 6 and 7 are children of MenuID 1, and so on.

Figure 2- Parent, Child Relationships

 

Step 2 - Add a Web Page That Implements a Menu and an XmlDataSource

Add a new WebForm to your web application. Drag and drop a Menu and an XmlDataSource from the toolbar onto the WebForm with the following properties.

Listing 2 - Menu and XmlDataSource Web Controls<asp:Menu ID="menu"DataSourceID="xmlDataSource" runat="server" BackColor="#FFFBD6"DynamicHorizontalOffset="2" Font-Names="Verdana" 

Page 3: Db Driven Hierarchical Menu Using Asp.Net 2.0

ForeColor="#990000"StaticSubMenuIndent="10px" StaticDisplayLevels="1" ><DataBindings>  <asp:MenuItemBindingDataMember="MenuItem" NavigateUrlField="NavigateUrl"  TextField="Text" ToolTipField="ToolTip"/></DataBindings><StaticSelectedStyleBackColor="#FFCC66" /><StaticMenuItemStyleHorizontalPadding="5px" VerticalPadding="2px" /><DynamicMenuStyle BackColor="#FFFBD6"/><DynamicSelectedStyleBackColor="#FFCC66" /><DynamicMenuItemStyle HorizontalPadding="5px"VerticalPadding="2px" /><DynamicHoverStyleBackColor="#990000" Font-Bold="False"ForeColor="White"/><StaticHoverStyle BackColor="#990000"Font-Bold="False" ForeColor="White" /></asp:Menu><asp:XmlDataSource ID="xmlDataSource"TransformFile="~/TransformXSLT.xsl"  XPath="MenuItems/MenuItem"runat="server"/> 

At runtime, the XmlDataSource object is assigned an XML string (shown in step 3) which is then transformed by the XSLT file, TransformXSLT.xsl to another XML format (XSLT is covered in step 4).  The transformed XML is then consumed by the Menu as specified by the Menu's DataSourceID property.

Note: We are using the XmlDataSource property, XPath, to introduce an optional way to exclude the XML root node, MenuItems.  If the root node is not excluded then the menu will contain an extra level which can be controlled using the menu property StaticDisplayLevels.  The MenuItems root nodes can also be excluded in XSLT.

Step 3 - Retrieve Data and Create Nested Relationships

Now it is time to retrieve and begin formatting the menu data for use by Microsoft's menu.  The challenge is to establish parent child relationships and then create a hierarchical representation of the data.   A DataSet object is perfect for this because it can store the structure of an entire database, including relationships, and then convert that relational data into nested XML. 

Add the following C# code to your Page_Load method.  This code uses a DataAdapter to retrieve data from the single database table and to fill a DataSet.  Once filled, a DataRelation is applied to the DataSet to establish MenuID and ParentID dependencies. Finally, a call to GetXML() retrieves a hierarchical XML representation of all relational data within the dataset.  

Listing 3 - The C# Codeusing System;using System.Xml;using System.Data;using System.Data.SqlClient; public partial class _Default:System.Web.UI.Page{  protected void Page_Load(object sender,EventArgs e)  {    DataSet ds = new DataSet();    string connStr = "server=localhost;Trusted_Connection=true;database=MenuDb";    using(SqlConnection conn = newSqlConnection(connStr))    {      string sql = "Select MenuID, Text,Description, ParentID from Menu";      SqlDataAdapter da = newSqlDataAdapter(sql, conn);      da.Fill(ds);      da.Dispose();    }    ds.DataSetName = "Menus";    ds.Tables[0].TableName = "Menu";

Page 4: Db Driven Hierarchical Menu Using Asp.Net 2.0

    DataRelation relation = newDataRelation("ParentChild",     ds.Tables["Menu"].Columns["MenuID"],     ds.Tables["Menu"].Columns["ParentID"], true);     relation.Nested = true;    ds.Relations.Add(relation);     xmlDataSource.Data = ds.GetXml();     if (Request.Params["Sel"] != null)      Page.Controls.Add(newSystem.Web.UI.LiteralControl("You selected " +        Request.Params["Sel"]));  }}

Note: You will have to supply your relevant SQL Server name, Username and Password in the above database connection string, connStr.

As shown in the screenshot below, the call to ds.GetXml() correctly displays the nested hierarchy.

Figure 3 - XML Generated By Using DataSet Relationships

Step 4 - Using XSLT to convert XML for Microsoft's Menu

The XML returned from ds.GetXml() now needs to be reformatted for Microsoft's Menu. XmlDataSource is perfect for this task because it can use XSLT to transform the above XML to another XML format and then provide that to Microsoft's menu.

The below XSLT code does just this.  It first finds the root node called Menus and applies the MenuListing template to its root children. Next, each Menu node's elements are converted to MenuItem attributes.  Finally, each Menu node is checked for the existence of children.  If children exist, then the MenuListing will be recursively called until all children are processed.

Page 5: Db Driven Hierarchical Menu Using Asp.Net 2.0

Add an XSLT file to your project named TransformXSLT.xsl with the following code.

Listing 5 - XSLT<?xml version="1.0"encoding="utf-8"?><xsl:stylesheet version="1.0"xmlns:xsl="http://www.w3.org/1999/XSL/Transform">  <xsl:output method="xml"indent="yes" encoding="utf-8"/>

  <!-- Replace root node name Menus with MenuItems       and call MenuListing for its children-->  <xsl:template match="/Menus">    <MenuItems>      <xsl:call-templatename="MenuListing" />    </MenuItems>  </xsl:template>    <!-- Allow for recursive child nodeprocessing -->  <xsl:templatename="MenuListing">    <xsl:apply-templatesselect="Menu" />  </xsl:template>    <xsl:template match="Menu">    <MenuItem>      <!-- Convert Menu child elements to MenuItem attributes -->      <xsl:attributename="Text">        <xsl:value-of select="Text"/>      </xsl:attribute>      <xsl:attributename="ToolTip">        <xsl:value-ofselect="Description"/>      </xsl:attribute>      <xsl:attributename="NavigateUrl">        <xsl:text>?Sel=</xsl:text>        <xsl:value-ofselect="Text"/>      </xsl:attribute>            <!-- Recursively call MenuListing forchild menu nodes -->      <xsl:if test="count(Menu) >0">        <xsl:call-templatename="MenuListing" />      </xsl:if>    </MenuItem>  </xsl:template></xsl:stylesheet>

Note: You can interactively debug an XSLT and an XML file from the IDE's XML Menu.

The XmlDataSource object's transformed XML that is provided to Microsoft's Menu is shown below.

Figure 4    

Step 5 - Run the Web Page

Page 6: Db Driven Hierarchical Menu Using Asp.Net 2.0

Run your web page to display the following menu.

Figure 5 - The Final Output

Downloads

[Download Sample]

Conclusion

This article shows how to create a menu using a self-join database table, SqlDataAdapter, DataSet, DataRelation, XML, XmlDataSource and XSLT using just a few lines of code.  The self-join table stores parent child menu relationships.  The SqlDataAdapter fills the Dataset.  The DataSet employs a DataRelation which is used to create a nested XML. XmlDataSource then applies the XSLT to the nested XML transforming it for use by Microsoft's Menu.

My next article will build upon this example and show how to create a WebForm that manipulates a database driven hierarchical menu.

Please provide feedback, letting me know how you liked this article.  Happy coding!

References

Use the below references to learn how to create table relationships, format menu styles and convert XML using XSLT.