Chapter 17. Using the Navigation Controls

<feature><title>In this Chapter</title> <objective>

Understanding Site Maps

</objective>
<objective>

Using the SiteMapPath Control

</objective>
<objective>

Using the Menu Control

</objective>
<objective>

Using the TreeView Control

</objective>
<objective>

Building a SQL Hierarchical Data Source Control

</objective>
<objective>

Summary

</objective>
</feature>

In this chapter, you learn how to use the SiteMapPath, Menu, and TreeView controls. All three of these controls can be used to enable users to navigate your website. Furthermore, the Menu and TreeView controls can be used independently of website navigation. You can bind these two controls to other data sources such as XML documents or database data.

This chapter explores different methods of binding the Menu and TreeView controls to different data sources and shows you how to format the rendered output of both of these controls. You also learn how to take advantage of AJAX when working with the TreeView control.

In the final section of this chapter, we build a SqlHierarchicalDataSource control, which enables you to bind controls such as the TreeView and Menu controls to hierarchical database data.

Understanding Site Maps

Before you learn about the navigation controls, you first need to understand Site Maps. All three navigation controls use Site Maps to retrieve navigation information. A Site Map enables you to represent the navigational relationships between the pages in an application, independent of the actual physical relationship between pages as stored in the file system.

Site Maps use the provider model. In the next chapter, you learn how to create custom Site Map providers to store Site Maps in custom data stores such as database tables. The examples in this chapter take advantage of the default XML Site Map provider, which enables you to store a Site Map in an XML file.

By default, the navigation controls assume the existence of an XML file named Web.sitemap, which is located in the root of your application.

For example, Listing 17.1 contains a simple Site Map.

Example 17.1. Web.sitemap

<?xml version="1.0" encoding="utf-8" ?>
<siteMap xmlns="http://schemas.microsoft.com/AspNet/SiteMap-File-1.0" >


<siteMapNode
  url="~/Default.aspx"
  title="Home"
  description="The home page of the Website">


  <!-- Product Nodes -->
  <siteMapNode
    title="Products"
    description="Website products">
    <siteMapNode
      url="~/Products/FirstProduct.aspx"
      title="First Product"
      description="The first product" />
    <siteMapNode
      url="~/Products/SecondProduct.aspx"
      title="Second Product"
      description="The second product" />
  </siteMapNode>


    <!-- Services Nodes -->
    <siteMapNode
      title="Services"
      description="Website services">
      <siteMapNode
        url="~/Service/FirstService.aspx"
        title="First Service"
        description="The first service" />
      <siteMapNode
        url="~/Products/SecondService.aspx"
        title="Second Service"
        description="The second service" />
    </siteMapNode>
    </siteMapNode>


</siteMapNode>


</siteMap>

A Site Map file contains <siteMapNode> elements. There can be only one top-level node. In the case of Listing 17.1, the top-level node represents the website’s homepage.

A <siteMapNode> supports three main attributes:

  • titleA brief title that you want to associate with a node.

  • descriptionA longer description that you want to associate with a node.

  • urlA URL that points to a page or other resource.

Notice that the url attribute is not required. Both the Products and Services nodes do not include a url attribute because these nodes do not represent pages to which you can navigate.

Each <siteMapNode> can contain any number of child nodes. In Listing 17.1, both the Products and Services nodes include two child nodes.

The Site Map in Listing 17.1 represents a website that has the following folder and page structure:

Default.aspx
Products
  FirstProduct.aspx
  SecondProduct.aspx
Services
  FirstService.aspx
  SecondService.aspx

The navigational structure of a website as represented by a Site Map is not required to have any relationship to the navigational structure of a website as stored in the file system. You can create any relationship between the nodes in a Site Map that you want.

Using the SiteMapPath Control

The SiteMapPath control enables you to navigate easily to any parent page of the current page. It displays the standard bread crumb trail that you see on many popular websites (see Figure 17.1).

Bread crumb trail at Yahoo.com.

Figure 17.1. Bread crumb trail at Yahoo.com.

You can use the SiteMapPath control simply by declaring the control in a page. The control automatically uses the Web.sitemap file located in the root of your application. For example, the page in Listing 17.2 includes the SiteMapPath control (see Figure 17.2).

Displaying the SiteMapPath control.

Figure 17.2. Displaying the SiteMapPath control.

Example 17.2. UsingSiteMapPath/DisplaySiteMapPath.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Display SiteMapPath</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:SiteMapPath
        id="SiteMapPath1"
        Runat="server" />


    <hr />


    <h1>Displaying a SiteMapPath Control</h1>


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

Notice that you can click the Home link rendered by the SiteMapPath control to navigate to the website’s home page.

The SiteMapPath uses both the title and description attributes from the <siteMapNode> elements contained in the Web.sitemap file. The title attribute is used for the node (link) text, and the description attribute is used for the node tool tip.

Note

Typically, you do not add a SiteMapPath control to individual pages in your website. If you add a SiteMapPath control to a Master Page, then you can display the SiteMapPath control automatically on every page. To learn more about Master Pages, see Chapter 5, “Designing Websites with Master Pages.”

The SiteMapPath control supports the following properties:

  • ParentLevelsDisplayEnables you to limit the number of parent nodes displayed. By default, a SiteMapPath control displays all the parent nodes.

  • PathDirectionEnables you to reverse the order of the links displayed by the SiteMapPath control. Possible values are RootToCurrent (the default) or CurrentToRoot.

  • PathSeparatorEnables you to specify the character used to separate the nodes displayed by the SiteMapPath control. The default value is >.

  • RenderCurrentNodeAsLinkEnables you to render the SiteMapPath node that represents the current page as a link. By default, the current node is not rendered as a link.

  • ShowToolTipsEnables you to disable the display of tool tips.

  • SiteMapProviderEnables you to specify the name of an alternate Site Map provider to use with the SiteMapPath control.

  • SkipLinkTextEnables you to specify more specific text for skipping the links displayed by the SiteMapPath control. The default value for this property is Skip Navigation Links.

Web Standards Note

All the navigation controls automatically render a skip navigation link to meet accessibility requirements. The skip navigation link is read by a screen reader, but it is not displayed in a normal browser.

If you are interacting with a web page through a screen reader, you don’t want to hear the list of navigation links each and every time you open a page. (It is the equivalent of listening to a phone menu every time you open a page.) The skip navigation link enables users of screen readers to skip the repetitive reading of links.

Formatting the SiteMapPath Control

You can use either styles or templates to format the SiteMapPath control.

The control supports the following Style objects:

  • CurrentNodeStyleFormats the SiteMapPath node that represents the current page.

  • NodeStyleFormats every node rendered by the SiteMapPath control.

  • PathSeparatorStyleFormats the text displayed between each SiteMapPath node.

  • RootNodeStyleFormats the root (first) node rendered by the SiteMapPath control.

For example, the page in Listing 17.3 takes advantage of all four Style properties to modify the default appearance of the SiteMapPath control (see Figure 17.3).

Using styles with the SiteMapPath control.

Figure 17.3. Using styles with the SiteMapPath control.

Example 17.3. UsingSiteMapPath/SiteMapPathStyle.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .siteMapPath
        {
            font:20px Comic Sans MS,Serif;
        }
        .currentNodeStyle
        {
            font-weight:bold;
        }
        .nodeStyle
        {
            text-decoration:none;
        }
        .pathSeparatorStyle
        {
            background-color:yellow;
            margin:10px;
            border:Solid 1px black;
        }
        .rootNodeStyle
        {
            text-decoration:none;
        }
    </style>
    <title>SiteMapPath Style</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:SiteMapPath
        id="SiteMapPath1"
        CssClass="siteMapPath"
        CurrentNodeStyle-CssClass="currentNodeStyle"
        NodeStyle-CssClass="nodeStyle"
        PathSeparatorStyle-CssClass="pathSeparatorStyle"
        RootNodeStyle-CssClass="rootNodeStyle"
        Runat="server" />


    <hr />


    <h1>SiteMapPath Style</h1>


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

Furthermore, you can use templates with the SiteMapPath control to format the appearance of the control (and change its behavior). The SiteMapPath control supports the following templates:

  • CurrentNodeTemplateTemplate for the SiteMapPath node that represents the current page.

  • NodeTemplateTemplate for each SiteMapPath node that is not the current or root node.

  • PathSeparatorTemplateTemplate for the text displayed between each SiteMapPath node.

  • RootNodeTemplateTemplate for the root (first) node rendered by the SiteMapPath control.

For example, the SiteMapPath control in Listing 17.4 includes a NodeTemplate. The NodeTemplate includes a HyperLink control that displays the current SiteMapPath node. The template also displays a count of the child nodes of the current node (see Figure 17.4).

Using a template with the SiteMapPath control.

Figure 17.4. Using a template with the SiteMapPath control.

Example 17.4. UsingSiteMapPath/SiteMapPathTemplates.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>SiteMapPath Templates</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:SiteMapPath
        id="SiteMapPath1"
        Runat="server">
        <NodeTemplate>
        <asp:HyperLink
            id="lnkPage"
            Text='<%# Eval("Title") %>'
            NavigateUrl='<%# Eval("Url") %>'
            ToolTip='<%# Eval("Description") %>'
            Runat="server" />
        [<%# Eval("ChildNodes.Count") %>]
        </NodeTemplate>
    </asp:SiteMapPath>


    <hr />


    <h1>SiteMapPath Templates</h1>


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

Within a template, the data item represents a SiteMapNode. Therefore, you can refer to any of the properties of the SiteMapNode class in a databinding expression.

Using the Menu Control

The Menu control enables you to create two types of menus. You can use the Menu control to create the left-column menu that appears in many websites. In other words, you can use the Menu control to display a vertical list of links.

You also can use the Menu control to create a menu that more closely resembles the drop-down menus that appear in traditional desktop applications. In this case, the Menu control renders a horizontal list of links.

Unlike the SiteMapPath control, the Menu control can represent other types of data than Site Map data. Technically, you can bind a Menu control to any data source that implements the IHiearchicalDataSource or IHiearchicalEnumerable interface.

In this section, you learn how to create different types of menus with the Menu control. First, you learn how to add menu items declaratively to a Menu control. Next, we discuss how the Menu control can be used with the MultiView control to display a tabbed page.

You also examine how you can bind the Menu control to different types of data sources. You learn how to use the Menu control with Site Map data, XML data, and database data.

Declaratively Adding Menu Items

You can display a menu with the Menu control by adding one or more Menu Item objects to its Items property. For example, the page in Listing 17.5 uses a Menu control to create a simple vertical menu (see Figure 17.5).

Displaying a menu with the Menu control.

Figure 17.5. Displaying a menu with the Menu control.

Example 17.5. MenuHyperLink.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Menu HyperLink</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:Menu
        id="Menu1"
        Runat="server">
        <Items>
            <asp:MenuItem
                Text="Products"
                NavigateUrl="Products.aspx" />
            <asp:MenuItem
                Text="Services"
                NavigateUrl="Services.aspx">
                <asp:MenuItem
                    Text="Training"
                    NavigateUrl="Training.aspx" />
                <asp:MenuItem
                    Text="Consulting"
                    NavigateUrl="Consulting.aspx" />
            </asp:MenuItem>
        </Items>
    </asp:Menu>


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

The Menu in Listing 17.5 is created from MenuItem objects. Each menu item in Listing 17.5 contains a link to another page.

Notice that MenuItem objects can be nested. The second MenuItem object—Services—includes two child MenuItem objects. When you hover your mouse over a parent menu item, the child menu items are displayed.

Each MenuItem in Listing 17.5 includes a Text and NavigateUrl property. Rather than use a MenuItem to link to a new page, you also can use a MenuItem to link back to the same page. In other words, each MenuItem can act like a Linkbutton control instead of a HyperLink control.

For example, each MenuItem object in Listing 17.6 includes a Text and Value property. When you click a menu item, the same page is reloaded and the value of the selected menu item is displayed (see Figure 17.6).

Selecting menu items.

Figure 17.6. Selecting menu items.

Example 17.6. MenuLinkButton.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">


    Protected Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs)
        lblMessage.Text = "You selected " & Menu1.SelectedValue
    End Sub


</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Menu LinkButton</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:Menu
        id="Menu1"
        OnMenuItemClick="Menu1_MenuItemClick"
        Runat="server">
        <Items>
            <asp:MenuItem
                Text="Products Page"
                Value="Products" />
            <asp:MenuItem
                Text="Services Page"
                Value="Services">
                <asp:MenuItem
                    Text="Training Page"
                    Value="Training" />
                <asp:MenuItem
                    Text="Consulting Page"
                    Value="Consulting" />
            </asp:MenuItem>
        </Items>
    </asp:Menu>


    <hr />


    <asp:Label
        id="lblMessage"
        EnableViewState="false"
        Runat="server" />


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

Notice that the page includes a MenuItemClick event handler. When you click a MenuItem (and the MenuItem does not have a NavigateUrl property), the MenuItemClick event is raised.

In Listing 17.6, the MenuItemClick handler displays the value of the selected MenuItem in a Label control.

Using the Menu Control with the MultiView Control

When the Menu control is used with the MultiView control, you can create tabbed pages. You use the Menu control to display the tabs, and the MultiView control to display the content that corresponds to the selected tab.

For example, the page in Listing 17.7 displays three tabs (see Figure 17.7).

Displaying a tabbed page.

Figure 17.7. Displaying a tabbed page.

Example 17.7. MenuTabStrip.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">


    Protected Sub menuTabs_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs)
        multiTabs.ActiveViewIndex = Int32.Parse(menuTabs.SelectedValue)
    End Sub


</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        html
         {
           background-color:silver;
         }
         .menuTabs
         {
             position:relative;
             top:1px;
             left:10px;
         }
         .tab
         {
            border:Solid 1px black;
            border-bottom:none;
            padding:0px 10px;
            background-color:#eeeeee;
         }
         .selectedTab
         {
             border:Solid 1px black;
             border-bottom:Solid 1px white;
             padding:0px 10px;
             background-color:white;
         }
         .tabBody
         {
             border:Solid 1px black;
             padding:20px;
             background-color:white;
         }
     </style>
     <title>Menu Tab Strip</title>
 </head>
 <body>
     <form id="form1" runat="server">
     <div>


     <asp:Menu
         id="menuTabs"
         CssClass="menuTabs"
         StaticMenuItemStyle-CssClass="tab"
         StaticSelectedStyle-CssClass="selectedTab"
         Orientation="Horizontal"
         OnMenuItemClick="menuTabs_MenuItemClick"
         Runat="server">
         <Items>
         <asp:MenuItem
             Text="Tab 1"
             Value="0"
             Selected="true" />
         <asp:MenuItem
             Text="Tab 2"
             Value="1"/>
         <asp:MenuItem
             Text="Tab 3"
             Value="2" />
 
         </Items>
     </asp:Menu>


     <div class="tabBody">
     <asp:MultiView
         id="multiTabs"
         ActiveViewIndex="0"
         Runat="server">
         <asp:View ID="view1" runat="server">


         Contents of first tab


        </asp:View>
        <asp:View ID="view2" runat="server">


        Contents of second tab


        </asp:View>
        <asp:View ID="view3" runat="server">


        Contents of third tab


        </asp:View>
    </asp:MultiView>
    </div>


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

After you open the page in Listing 17.7 and click a tab, the MenuItemClick event is raised. The MenuItemClick event handler changes the ActiveViewIndex property of the MultiView control to display the content of the selected tab.

Web Standards Note

The Menu control in Listing 17.7 is pushed down one pixel and pushed right 10 pixels to hide the border between the selected tab and the contents of the tab. (The Menu control has a relative position.) Notice that the style rule for the selected tab includes a white bottom border. This trick works in Internet Explorer 6, Firefox 1, and Opera 8.

Binding to a Site Map

Like the SiteMapPath control, you can use the Menu control with a Site Map. Users can click menu items to navigate to particular pages in your website.

Unlike the SiteMapPath control, however, the Menu control does not automatically bind to a Site Map. You must explicitly bind the Menu control to a SiteMapDataSource control to display nodes from a Site Map.

For example, the page in Listing 17.8 contains a menu that contains links to all the pages in a website (see Figure 17.8).

Displaying a Site Map with a Menu control.

Figure 17.8. Displaying a Site Map with a Menu control.

Example 17.8. UsingMenu/MenuSiteMap.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Menu SiteMap</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:Menu
        id="Menu1"
        DataSourceID="srcSiteMap"
        Runat="server" />


    <asp:SiteMapDataSource
        id="srcSiteMap"
        Runat="server" />


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

When you initially open the page in Listing 17.8, the only menu item that appears is the link to the Home page. If you hover your mouse over this link, links to additional pages are displayed.

Normally, you do not want the Home link to be displayed in a navigation menu. Instead, you want to display the second level of menu items. You can use the ShowStartingNode property of the SiteMapDataSource control to hide the topmost node in a Site Map.

For example, the page in Listing 17.9 uses a Menu control that renders a standard left-column navigational menu (see Figure 17.9).

Displaying a navigation menu.

Figure 17.9. Displaying a navigation menu.

Example 17.9. UsingMenu/MenuNavigate.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        html
        {
            background-color:silver;
        }
        .navigation
        {
            float:left;
            width:280px;
            height:500px;
            padding:20px;
            background-color:#eeeeee;
        }
        .content
        {
            float:left;
            width:550px;
            height:500px;
            padding:20px;
            background-color:white;
        }
        .menuItem
        {
            border:Outset 1px black;
            background-color:Gray;
            font:14px Arial;
            color:White;
            padding:8px;
        }
    </style>
    <title>Menu Navigate</title>
</head>
<body>
    <form id="form1" runat="server">


    <div class="navigation">


    <asp:Menu
        id="Menu1"
        DataSourceID="srcSiteMap"
        StaticMenuItemStyle-CssClass="menuItem"
        DynamicMenuItemStyle-CssClass="menuItem"
        Runat="server" />


    <asp:SiteMapDataSource
        id="srcSiteMap"
        ShowStartingNode="false"
        Runat="server" />


    </div>


    <div class="content">

    <h1>Displaying a Website menu with the Menu control</h1>


    </div>


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

When you open the page in Listing 17.9, the second-level nodes from the Site Map are initially displayed. Furthermore, the Menu control is styled to appear more like a traditional website navigation menu.

Binding to an XML File

As an alternative to binding a Menu control to a SiteMapDataSource control, you can bind the control to an XML document by using the XmlDataSource control. For example, suppose that you have the XML file in Listing 17.10.

Example 17.10. Menu.xml

<?xml version="1.0" encoding="utf-8" ?>
<menu>
  <appetizer>
    <soup />
    <cheese />
  </appetizer>
  <entree>
    <duck />
    <chicken />
  </entree>
  <dessert>
    <cake />
    <pie />
  </dessert>
</menu>

The page in Listing 17.11 displays the contents of Listing 17.10 by using an XmlDataSource control to represent the XML document.

Example 17.11. MenuXML.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Menu XML</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:Menu
        id="Menu1"
        DataSourceID="srcMenu"
        Runat="server" />


    <asp:XmlDataSource
        id="srcMenu"
        DataFile="Menu.xml"
        Runat="server" />


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

When using the XmlDataSource control, you can use the XPath property to supply an xpath query that restricts the nodes returned by the XmlDataSource. You also can use either the Transform or TransformFile property to apply an XSLT Style Sheet to the XML document and transform the nodes returned by the XmlDataSource.

The XML file in Listing 17.10 is very simple. The nodes do not contain any attributes. When you bind the Menu control to the XML file, the ToString() method is called on each XML file node.

You also can bind the Menu control to more complex XML documents. For example, the item nodes in the XML document in Listing 17.12 include two attributes: text and price.

Example 17.12. MenuComplex.xml

<?xml version="1.0" encoding="utf-8" ?>
<menu>
  <category text="appetizer">
    <item text="soup" price="12.56" />
    <item text="cheese" price="17.23" />
  </category>
  <category text="entree">
    <item text="duck" price="89.21" />
    <item text="chicken" price="34.56" />
  </category>
  <category text="dessert">
    <item text="cake" price="23.43" />
    <item text="pie" price="115.46" />
  </category>
</menu>

When you bind to the XML document in Listing 17.12, you must specify one or more menu item bindings. The menu item bindings specify the relationship between node attributes and the menu items displayed by the Menu control.

The Menu control in Listing 17.13 includes MenuItemBinding subtags (see Figure 17.10).

Displaying an XML document with the Menu control.

Figure 17.10. Displaying an XML document with the Menu control.

Example 17.13. MenuXMLComplex.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Menu XML Complex</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:Menu
        id="Menu1"
        DataSourceID="srcMenu"
        Runat="server">
        <DataBindings>
        <asp:MenuItemBinding
            DataMember="category"
            TextField="text" />
        <asp:MenuItemBinding
            DataMember="item"
            TextField="text"
            ValueField="price" />
        </DataBindings>
    </asp:Menu>


    <asp:XmlDataSource
        id="srcMenu"
        DataFile="MenuComplex.xml"
        Runat="server" />

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

Notice that the Menu control includes a <DataBindings> element. This element includes two MenuItemBinding subtags. The first subtag represents the relationship between the category nodes in the XML file and the menu items. The second subtag represents the relationship between the item nodes in the XML file and the menu items.

Binding to Database Data

You can’t bind a Menu control directly to database data. Neither the SqlDataSource nor ObjectDataSource controls implement the IHierachicalDataSource interface. Therefore, if you want to represent database data with the Menu control, then you need to perform some more work.

One option is to create your own SqlHiearachicalDataSource control. You can do this either by deriving from the base HiearchicalDataSourceControl class or implementing the IHiearchicalDataSource interface. We’ll take this approach in the final section of this chapter, when we create a custom SqlHierarchicalDataSource control.

A second option is to build the menu items programmatically in the Menu control. This is the approach that is followed here.

Imagine that you want to represent the contents of the following database table with a Menu control:

CategoryId

ParentId

Name

1

null

Beverages

2

null

Fruit

3

1

Milk

4

1

Juice

5

4

Apple Juice

6

4

Orange Juice

7

2

Apples

8

2

Pears

This database table represents product categories. The categories are nested with the help of the ParentId column. For example, the Orange Juice category is nested below the Juice category, and the Juice category is nested below the Beverages category.

The page in Listing 17.14 illustrates how you can display this database table with a Menu control (see Figure 17.11).

Displaying database data with the Menu control.

Figure 17.11. Displaying database data with the Menu control.

Example 17.14. MenuDatabase.aspx

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Web.Configuration" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">


    ''' <summary>
    ''' Only populate the menu when the page first loads
    ''' </summary>
    Private Sub Page_Load()
        If Not Page.IsPostBack Then
            PopulateMenu()
        End If
    End Sub


    ''' <summary>
    ''' Get the data from the database and create the top-level
    ''' menu items
    ''' </summary>
    Private Sub PopulateMenu()
        Dim menuData As DataTable = GetMenuData()
        AddTopMenuItems(menuData)
    End Sub


    ''' <summary>
    ''' Use a DataAdapter and DataTable to grab the database data
    ''' </summary>
    ''' <returns></returns>
    Private Function GetMenuData() As DataTable
        ' Get Categories table
        Dim selectCommand As String = "SELECT CategoryId,ParentId,Name FROM Categories"
        Dim conString As String = WebConfigurationManager.ConnectionStrings("Categories").ConnectionString
        Dim dad As SqlDataAdapter = New SqlDataAdapter(selectCommand, conString)
        Dim dtblCategories As DataTable = New DataTable()
        dad.Fill(dtblCategories)
        Return dtblCategories
    End Function


    ''' <summary>
    ''' Filter the data to get only the rows that have a
    ''' null ParentID (these are the top-level menu items)
    ''' </summary>
    Private Sub AddTopMenuItems(ByVal menuData As DataTable)
        Dim view As DataView = New DataView(menuData)
        view.RowFilter = "ParentID IS NULL"
        Dim row As DataRowView
        For Each row In view
            Dim NewMenuItem As MenuItem = New MenuItem(row("Name").ToString(), row("CategoryId").ToString())
            Menu1.Items.Add(NewMenuItem)
            AddChildMenuItems(menuData, NewMenuItem)
        Next


    End Sub


    ''' <summary>
    ''' Recursively add child menu items by filtering by ParentID
    ''' </summary>
    Private Sub AddChildMenuItems(ByVal menuData As DataTable, ByVal parentMenuItem As MenuItem)
        Dim view As DataView = New DataView(menuData)
        view.RowFilter = "ParentID=" + parentMenuItem.Value
        Dim row As DataRowView
        For Each row In view
            Dim NewMenuItem As MenuItem = New MenuItem(row("Name").ToString(),  row("CategoryId").ToString())
            parentMenuItem.ChildItems.Add(NewMenuItem)
            AddChildMenuItems(menuData, NewMenuItem)
        Next

    End Sub


</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .menuItem
        {
            border:Solid 1px black;
            width:100px;
            padding:2px;
            background-color:#eeeeee;
        }
        .menuItem a
        {
            color:blue;
        }
        .grid
        {
            margin-top:10px;
        }


        .grid td, .grid th
        {
            padding:10px;
        }
    </style>
    <title>Menu Database</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:Menu
        id="Menu1"
        Orientation="horizontal"
        StaticMenuItemStyle-CssClass="menuItem"
        DynamicMenuItemStyle-CssClass="menuItem"
        Runat="server" />


    <asp:GridView
        id="grdProducts"
        DataSourceID="srcProducts"
        CssClass="grid"
        AutoGenerateColumns="false"
        Runat="server">
        <Columns>
        <asp:BoundField
            DataField="ProductName"
            HeaderText="Product" />
        <asp:BoundField
            DataField="Price"
            HeaderText="Price"
            DataFormatString="{0:c}" />
        </Columns>
    </asp:GridView>


    <asp:SqlDataSource
        id="srcProducts"
        ConnectionString="<%$ ConnectionStrings:Categories %>"
        SelectCommand="SELECT ProductName,Price FROM Products
            WHERE CategoryId=@CategoryId"
        Runat="server">
        <SelectParameters>
        <asp:ControlParameter
            Name="CategoryId"
            ControlID="Menu1" />
        </SelectParameters>
    </asp:SqlDataSource>


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

The menu items are added to the Menu control in the PopulateMenu() method. This method first grabs a DataTable that contains the contents of the Categories database table. Next, it creates a menu item for each row that does not have a parent row (each row where the ParentId column has the value null).

The child menu items for each menu item are added recursively. The ParentId column is used to filter the contents of the Categories DataTable.

The page in Listing 17.14 also includes a GridView control that displays a list of products that match the category selected in the menu. The GridView is bound to a SqlDataSource control, which includes a ControlParameter that filters the products based on the selected menu item.

Formatting the Menu Control

The Menu control supports an abundance of properties that can be used to format the appearance of the control. Many of these properties have an effect on static menu items, and many of these properties have an effect on dynamic menu items. Static menu items are menu items that always appear. Dynamic menu items are menu items that appear only when you hover your mouse over another menu item.

First, the Menu control supports the following general properties related to formatting:

  • DisappearAfterEnables you to specify the amount of time, in milliseconds, that a dynamic menu item is displayed after a user moves the mouse away from the menu item.

  • DynamicBottomSeparatorImageUrlEnables you to specify the URL to an image that appears under each dynamic menu item.

  • DynamicEnableDefaultPopOutImageEnables you to disable the image (triangle) that indicates that a dynamic menu item has child menu items.

  • DynamicHorizontalOffsetEnables you to specify the number of pixels that a dynamic menu item is shifted relative to its parent menu item.

  • DynamicItemFormatStringEnables you to format the text displayed in a dynamic menu item.

  • DynamicPopOutImageTextFormatStringEnables you to format the alt text displayed for the popout image.

  • DynamicPopOutImageUrlEnables you to specify the URL for the dynamic popout image. (By default, a triangle is displayed.)

  • DynamicTopSeparatorImageUrlEnables you to specify the URL to an image that appears above each dynamic menu item.

  • DynamicVerticalOffsetEnables you to specify the number of pixels that a dynamic menu item is shifted relative to its parent menu item.

  • ItemWrapEnables you to specify whether the text in menu items should wrap.

  • MaximumDynamicDisplayLevelsEnables you to specify the maximum number of levels of dynamic menu items to display.

  • OrientationEnables you to display a menu horizontally or vertically (the default value is Vertical).

  • ScollDownImageUrlEnables you to specify the URL to an image that is displayed and that enables you to scroll down through menu items.

  • ScrollDownTextEnables you to specify alt text for the ScrollDown image.

  • ScrollUpImageUrlEnables you to specify the URL to an image that is displayed and that enables you to scroll up through menu items.

  • ScrollUpTextEnables you to specify alt text for the ScrollUp image.

  • SkipLinkTextEnables you to modify the text displayed by the skip link. (The skip link enables blind users to skip past the contents of a menu.)

  • StaticBottomSeparatorImageUrlEnables you to specify the URL to an image that appears below each static menu item.

  • StaticDisplayLevelsEnables you to specify the number of static levels of menu items to display.

  • StaticEnableDefaultPopOutImageEnables you to disable the default popout image that indicates that a menu item has child menu items.

  • StaticItemFormatStringEnables you to format the text displayed in each static menu item.

  • StaticImagePopOutFormatStringEnables you to specify the alt text displayed by the popout image.

  • StaticPopOutImageUrlEnables you to specify the URL for the popout image.

  • StaticSubMenuIndentEnables you to specify the number of pixels that a static menu item is indented relative to its parent menu item.

  • StaticTopSeparatorImageUrlEnables you to specify the URL to an image that appears above each static menu item.

  • TargetEnables you to specify the window in which a new page opens when you click a menu item.

This list includes several interesting properties. For example, notice that you can specify images for scrolling up and down through a list of menu items. These images appear when you constrain the height of either the static or dynamic menu.

The Menu control also exposes several Style objects. You can use these Style objects as hooks to which you can attach Cascading Style Sheet classes:

  • DynamicHoverStyleStyle applied to a dynamic menu item when you hover your mouse over it.

  • DynamicMenuItemStyleStyle applied to each dynamic menu item.

  • DynamicMenuStyleStyle applied to the container tag for the dynamic menu.

  • DynamicSelectedStyleStyle applied to the selected dynamic menu item.

  • StaticHoverStyleStyle applied to a static menu item when you hover your mouse over it.

  • StaticMenuItemStyleStyle applied to each static menu item.

  • StaticMenuStyleStyle applied to the container tag for the static menu.

  • StaticSelectedStyleStyle applied to the selected static menu item.

Furthermore, you can apply styles to menu items based on their level in the menu. For example, you might want the font size to get progressively smaller depending on how deeply nested a menu item is within a menu. You can use three properties of the Menu control to format menu items, depending on their level:

  • LevelMenuItemStylesContains a collection of MenuItemStyle controls, which correspond to different menu levels.

  • LevelSelectedStylesContains a collection of MenuItemStyle controls, which correspond to different menu levels of selected menu items.

  • LevelSubMenuStylesContains a collection of MenuItemStyle controls, which correspond to different menu levels of static menu items.

For example, the page in Listing 17.15 illustrates how you can apply different formatting to menu items that appear at different menu levels (see Figure 17.12).

Applying styles to different menu levels.

Figure 17.12. Applying styles to different menu levels.

Example 17.15. MenuLevelStyles.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .menuLevel1
        {
            font:40px Arial,Sans-Serif;
        }
        .menuLevel2
        {
            font:20px Arial,Sans-Serif;
        }
        .menuLevel3
        {
            font:10px Arial,Sans-Serif;
        }
    </style>
    <title>Menu Level Styles</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:Menu
        id="Menu1"
        Runat="server">
        <LevelMenuItemStyles>
            <asp:MenuItemStyle CssClass="menuLevel1" />
            <asp:MenuItemStyle CssClass="menuLevel2" />
            <asp:MenuItemStyle CssClass="menuLevel3" />
        </LevelMenuItemStyles>
        <Items>
        <asp:MenuItem Text="Produce">
            <asp:MenuItem Text="Apples" />
            <asp:MenuItem Text="Oranges" />
        </asp:MenuItem>
        <asp:MenuItem Text="Beverages">
            <asp:MenuItem Text="Soda">
                <asp:MenuItem Text="Coke" />
                <asp:MenuItem Text="Pepsi" />
            </asp:MenuItem>
        </asp:MenuItem>
        </Items>
    </asp:Menu>


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

The MenuItemStyle controls are applied to the menu level that corresponds to their order of declaration. The first MenuItemStyle is applied to the first menu level, the second MenuItemStyle is applied to the second menu level, and so on.

Finally, the MenuItem class itself includes several useful formatting properties:

  • ImageUrlEnables you to specify the URL for an image that is displayed next to a menu item.

  • PopOutImageUrlEnables you to specify the URL for an image that is displayed when a menu item contains child menu items.

  • SeparatorImageUrlEnables you to specify the URL for an image that appears below a menu item.

  • SelectableEnables you to prevent users from selecting (clicking) a menu item.

  • SelectedEnables you to specify whether a menu item is selected.

  • TargetEnables you to specify the name of the window that opens when you click a menu item.

For example, the page in Listing 17.16 displays a menu that resembles a traditional desktop application menu (see Figure 17.13).

Displaying a desktop application menu.

Figure 17.13. Displaying a desktop application menu.

Example 17.16. MenuDesktop.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .staticMenuItem
        {
            color:black;
            border:solid 1px black;
            padding:2px 4px;
        }

        .menuHover
        {
            color:white;
            background-color:blue;
        }
        .dynamicMenuItem
        {
            color:black;
            padding:2px 4px;
        }
        .dynamicMenu
        {
            border:Solid 1px black;
            filter:progid:DXImageTransform.Microsoft.dropshadow(OffX=5, OffY=5,
 Color='gray', Positive='true')"
        }
    </style>
    <title>Menu Desktop</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:Menu
        id="Menu1"
        Orientation="Horizontal"
        StaticMenuItemStyle-CssClass="staticMenuItem"
        StaticHoverStyle-CssClass="menuHover"
        DynamicHoverStyle-CssClass="menuHover"
        DynamicMenuItemStyle-CssClass="dynamicMenuItem"
        DynamicMenuStyle-CssClass="dynamicMenu"
        Runat="server">
        <Items>
        <asp:MenuItem
            Text="File"
            Selectable="false">
            <asp:MenuItem
                Text="Save" />
            <asp:MenuItem
                Text="Open" />
        </asp:MenuItem>
        <asp:MenuItem
            Text="Format"
            Selectable="false">
            <asp:MenuItem
                Text="Bold"
                ImageUrl="Images/Bold.gif" />
            <asp:MenuItem
                Text="Italic"
                ImageUrl="Images/Italic.gif" />
            <asp:MenuItem
                Text="Underline"
                ImageUrl="Images/Underline.gif"
                SeparatorImageUrl="Images/Divider.gif" />
            <asp:MenuItem
                Text="Left Align"
                ImageUrl="Images/JustifyLeft.gif" />
            <asp:MenuItem
                Text="Center Align"
                ImageUrl="Images/JustifyCenter.gif" />
            <asp:MenuItem
                Text="Right Align"
                ImageUrl="Images/JustifyRight.gif" />
        </asp:MenuItem>
        </Items>
    </asp:Menu>


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

Using Templates with the Menu Control

The Menu control supports templates. You can use templates to completely customize the appearance of the Menu control.

The Menu control supports the following two templates:

  • DynamicItemTemplateTemplate applied to dynamic menu items.

  • StaticItemTemplateTemplate applied to static menu items.

The page in Listing 17.17 uses both templates to display menu items. The templates display a count of child items for each menu item (see Figure 17.14).

Using templates with the Menu control.

Figure 17.14. Using templates with the Menu control.

Example 17.17. MenuTemplates.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">

    Protected Sub Menu1_MenuItemClick(ByVal sender As Object, ByVal e As MenuEventArgs)
        lblMessage.Text = Menu1.SelectedValue
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .menuItem
        {
            color:black;
            border:Solid 1px Gray;
            background-color:#c9c9c9;
            padding:2px 5px;
        }
    </style>
    <title>Menu Templates</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:Menu
        id="Menu1"
        OnMenuItemClick="Menu1_MenuItemClick"
        Orientation="Horizontal"
        StaticMenuItemStyle-CssClass="menuItem"
        DynamicMenuItemStyle-CssClass="menuItem"
        Runat="server">
        <StaticItemTemplate>
        <%# Eval("Text") %>
        (<%# Eval("ChildItems.Count") %>)
        </StaticItemTemplate>
        <DynamicItemTemplate>
        <%# Eval("Text") %>
        (<%# Eval("ChildItems.Count") %>)
        </DynamicItemTemplate>
        <Items>
        <asp:MenuItem Text="Produce">
            <asp:MenuItem Text="Apples" />
            <asp:MenuItem Text="Oranges" />
        </asp:MenuItem>
        <asp:MenuItem Text="Beverages">
            <asp:MenuItem Text="Soda">
                <asp:MenuItem Text="Coke" />
                <asp:MenuItem Text="Pepsi" />
            </asp:MenuItem>
        </asp:MenuItem>
        </Items>
    </asp:Menu>


    <hr />


    <asp:Label
        id="lblMessage"
        EnableViewState="false"
        Runat="server" />

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

Notice that you do not need to create LinkButton controls in the templates. The content of the template is wrapped in a link automatically when it is appropriate.

Using the TreeView Control

The TreeView control is very similar to the Menu control. Like the Menu control, you can use the TreeView control to display hierarchical data. The TreeView control binds to any data source that implements the IHierarchicalDataSource or IHiearchicalEnumerable interface.

In this section, you learn how to add items declaratively to the TreeView control. You also learn how to bind a TreeView control to hierarchical data sources such as the SiteMapDataSource and XmlDataSource controls.

You also see how you can use the TreeView control with database data. A TreeView is built programmatically from database data.

Finally, you learn how you can use AJAX with the TreeView control to display large sets of data efficiently. By taking advantage of AJAX, you can update a TreeView without posting a page back to the server.

Declaratively Adding Tree Nodes

A TreeView control is made up of TreeNode objects. You can build a TreeView control by declaring TreeNode objects in the TreeView control’s Items collection.

For example, Listing 17.18 contains a TreeView which renders a nested set of links to pages (see Figure 17.15).

Example 17.18. TreeViewDeclare.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>TreeView Declare</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:TreeView
        id="TreeView1"
        Runat="server">
        <Nodes>
        <asp:TreeNode
            Text="Home"
            NavigateUrl="~/Default.aspx">
            <asp:TreeNode
                Text="Products">
                <asp:TreeNode
                    Text="First Product"
                    NavigateUrl="~/Products/FirstProduct.aspx" />
                <asp:TreeNode
                    Text="Second Product"
                    NavigateUrl="~/Products/SecondProduct.aspx" />
            </asp:TreeNode>
            <asp:TreeNode
                Text="Services">
                <asp:TreeNode
                    Text="First Service"
                    NavigateUrl="~/Services/FirstService.aspx" />
                <asp:TreeNode
                    Text="Second Service"
                    NavigateUrl="~/Services/SecondService.aspx" />
            </asp:TreeNode>
        </asp:TreeNode>
        </Nodes>
    </asp:TreeView>


    </div>
    </form>
</body>
</html>
Displaying a TreeView control.

Figure 17.15. Displaying a TreeView control.

Some of the TreeNodes in Listing 17.18 include a Text property, and some of the TreeNodes include both a Text and NavigateUrl property. You can click the TreeNodes that include a NavigateUrl property to link to a new page.

You also can associate a Value property with a TreeNode. This is useful when you want to post back to the same page. For example, the page in Listing 17.19 enables you to display the value of the selected TreeNode in a Label control (see Figure 17.16).

Selecting a TreeView node.

Figure 17.16. Selecting a TreeView node.

Example 17.19. TreeViewValue.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">

    Protected Sub TreeView1_SelectedNodeChanged(ByVal sender As Object, ByVal e As EventArgs)
        lblMessage.Text = TreeView1.SelectedValue
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        html
        {
            background-color:silver;
        }
        .content
        {
            float:left;
            width:350px;
            height:500px;
            padding:20px;
            margin:10px;
            background-color:white;
        }
    </style>
    <title>TreeView Value</title>
</head>
<body>
    <form id="form1" runat="server">

    <div class="content">
    <asp:TreeView
        id="TreeView1"
        OnSelectedNodeChanged="TreeView1_SelectedNodeChanged"
        Runat="server" >
        <Nodes>
        <asp:TreeNode
            Text="Home"
            Value="Home">
            <asp:TreeNode
                Text="Products">
                <asp:TreeNode
                    Text="First Product"
                    Value="FirstProduct" />
                <asp:TreeNode
                    Text="Second Product"
                    Value="SecondProduct" />
            </asp:TreeNode>
            <asp:TreeNode
                Text="Services">
                <asp:TreeNode
                    Text="First Service"
                    Value="FirstService" />
                <asp:TreeNode
                    Text="Second Service"
                    Value="SecondService" />
            </asp:TreeNode>
        </asp:TreeNode>
        </Nodes>
    </asp:TreeView>
    </div>

    <div class="content">
    You selected:
    <asp:Label
        id="lblMessage"
        EnableViewState="false"
        Runat="server" />
    </div>


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

Notice that the page in Listing 17.19 includes a SelectedNodeChanged event handler. When you select a new node, the SelectedNodeChanged event handler displays the value of the selected TreeNode in a Label control.

Displaying Check Boxes with the TreeView Control

You can display check boxes next to each node in a TreeView control by assigning a value to the ShowCheckBoxes property. This property accepts the following values:

  • All

  • Leaf

  • None

  • Parent

  • Root

You can use a bitwise combination of these values when specifying the nodes to display with check boxes.

The page in Listing 17.20 illustrates the ShowCheckBoxes property (see Figure 17.17).

Displaying TreeView check boxes.

Figure 17.17. Displaying TreeView check boxes.

Example 17.20. TreeViewCheckBoxes.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">

    Protected Sub btnSubscribe_Click(ByVal sender As Object, ByVal e As EventArgs)
        For Each node As TreeNode In TreeView1.CheckedNodes
            bltSubscribed.Items.Add(node.Text)
        Next
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>TreeView CheckBoxes</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    Select the Newsgroups which you
    would like to join:


    <br />


    <asp:TreeView
        id="TreeView1"
        ShowCheckBoxes="Leaf"
        Runat="server">
        <Nodes>
        <asp:TreeNode
            Text="Programming">
            <asp:TreeNode Text="ASP.NET" />
            <asp:TreeNode Text="JAVA" />
            <asp:TreeNode Text="Cold Fusion" />
        </asp:TreeNode>
        <asp:TreeNode
            Text="Sports">
            <asp:TreeNode Text="Baseball" />
            <asp:TreeNode Text="Hockey" />
            <asp:TreeNode Text="Football" />
        </asp:TreeNode>
        </Nodes>
    </asp:TreeView>


    <br />


    <asp:Button
        id="btnSubscribe"
        Text="Subscribe"
        OnClick="btnSubscribe_Click"
        Runat="server" />


    <hr />


    You selected:

    <asp:BulletedList
        id="bltSubscribed"
        EnableViewState="false"
        Runat="server" />

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

The page in Listing 17.20 displays nested newsgroups. You can subscribe to the newsgroups by clicking the Subscribe button.

When you click the Subscribe button, the CheckedNodes property is used to return a list of all of the checked TreeNodes. This list is displayed in a BulletedList control.

Binding to a Site Map

You can use a TreeView control as a navigation element in your pages by binding the TreeView to a Site Map. The page in Listing 17.21 demonstrates how you can bind a TreeView to a SiteMapDataSource control (see Figure 17.18).

Displaying a Site Map with a TreeView control.

Figure 17.18. Displaying a Site Map with a TreeView control.

Example 17.21. UsingTreeView/TreeViewSiteMap.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>TreeView Site Map</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:TreeView
        id="TreeView1"
        DataSourceID="srcSiteMap"
        Runat="server" />


    <asp:SiteMapDataSource
        id="srcSiteMap"
        Runat="server" />

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

When you open the page in Listing 17.21, all the nodes from the Site Map are displayed automatically in the TreeView control. By default, the SiteMapDataSource uses the XmlSiteMapProvider, which represents a file named Web.sitemap located at the root of an application.

Note

You can add a TreeView and SiteMapDataSource control to a Master Page to show the TreeView in multiple pages. To learn more about Master Pages, see Chapter 5, “Designing Websites with Master Pages.”

Binding to an XML File

Because an XmlDataSource control returns hierarchical data, you can bind a TreeView directly to an XmlDataSource. For example, imagine that you need to display the XML document contained in Listing 17.22.

Example 17.22. Movies.xml

<?xml version="1.0" encoding="utf-8" ?>
<movies>
  <action>
    <StarWars />
    <IndependenceDay />
  </action>
  <horror>
    <Jaws />
    <NightmareBeforeChristmas />
  </horror>
</movies>

The page in Listing 17.23 illustrates how you can display the contents of this XML document with a TreeView control.

Example 17.23. TreeViewXml.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>TreeView XML</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:TreeView
        id="TreeView1"
        DataSourceID="srcMovies"
        Runat="server" />

     <asp:XmlDataSource
        id="srcMovies"
        DataFile="~/Movies.xml"
        Runat="server" />

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

The Movies.xml document in Listing 17.22 is extremely simple. The elements do not include any attributes. You can display more complicated XML documents with the TreeView control by declaring one or more TreeNodeBinding elements.

For example, the nodes in the XML document in Listing 17.24 include id and text attributes.

Example 17.24. MoviesComplex.xml

<?xml version="1.0" encoding="utf-8" ?>
<movies>
  <category id="category1" text="Action">
    <movie id="movie1" text="Star Wars" />
    <movie id="movie2" text="Independence Day" />
  </category>
  <category id="category2" text="Horror">
    <movie id="movie3" text="Jaws" />
    <movie id="movie4" text="Nightmare Before Christmas" />
  </category>
</movies>

The page in Listing 17.25 displays the contents of the XML document in Listing 17.24.

Example 17.25. TreeViewXMLComplex.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>TreeView XML Complex</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:TreeView
        id="TreeView1"
        DataSourceID="srcMovies"
        Runat="server">
        <DataBindings>
        <asp:TreeNodeBinding
            DataMember="category"
            TextField="text"
            ValueField="id" />
        <asp:TreeNodeBinding
            DataMember="movie"
            TextField="text"
            ValueField="id" />
        </DataBindings>
    </asp:TreeView>


    <asp:XmlDataSource
        id="srcMovies"
        DataFile="~/MoviesComplex.xml"
        Runat="server" />

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

The TreeView in Listing 17.25 includes a DataBindings subtag. This tag includes two TreeNodeBinding elements. The first TreeNodeBinding specifies the relationship between <category> nodes in the XML document and TreeView nodes. The second TreeNodeBinding specifies the relationship between <movie> nodes and TreeView nodes.

Binding to Database Data

You cannot bind a TreeView control directly to a SqlDataSource or ObjectDataSource control because neither of these two controls expose hierarchical data. If you want to display database data with the TreeView control then you have a choice: create a custom SqlHierarchicalDataSource control or programmatically bind the TreeView to the database data.

The hard option is to build a SQL hierarchical DataSource control. You can do this by deriving a new control from the base HierarchicalDataSourceControl class or by implementing the IHierarchicalDataSource interface. We explore this option in the final section of this chapter.

The second option is to build the TreeView control programmatically from a set of database records. This is the approach that we will follow in this section.

Imagine that you have a database table that looks like this:

MessageId

ParentId

Subject

1

null

How do you use the Menu control?

2

null

What is the TreeView control?

3

1

RE:How do you use the Menu control?

4

1

RE:How do you use the Menu control?

5

2

RE:What is the TreeView control?

6

5

RE:RE:What is the TreeView control?

This database table represents a discussion forum. The relationship between the messages is determined by the ParentId column. The messages that have a null ParentID represent the threads, and the other messages represent replies to the threads.

The page in Listing 17.26 uses a TreeView control to display the contents of the Discuss database table (see Figure 17.19).

Displaying database data with a TreeView control.

Figure 17.19. Displaying database data with a TreeView control.

Example 17.26. TreeViewDatabase.aspx

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Web.Configuration" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">


    ''' <summary>
    ''' Only populate the TreeView when the page first loads
    ''' </summary>
    Private Sub Page_Load()
        If Not Page.IsPostBack Then
            PopulateTreeView()
        End If
    End Sub


    ''' <summary>
    ''' Get the data from the database and create the top-level
    ''' TreeView items
    ''' </summary>
    Private Sub PopulateTreeView()
        Dim treeViewData As DataTable = GetTreeViewData()
        AddTopTreeViewNodes(treeViewData)
    End Sub


    ''' <summary>
    ''' Use a DataAdapter and DataTable to grab the database data
    ''' </summary>
    ''' <returns></returns>
    Private Function GetTreeViewData() As DataTable
        ' Get Discuss table
        Dim selectCommand As String = "SELECT MessageId,ParentId,Subject FROM Discuss"
        Dim conString As String = WebConfigurationManager.ConnectionStrings("Discuss").ConnectionString
        Dim dad As SqlDataAdapter = New SqlDataAdapter(selectCommand, conString)
        Dim dtblDiscuss As DataTable = New DataTable()
        dad.Fill(dtblDiscuss)
        Return dtblDiscuss
    End Function


    ''' <summary>
    ''' Filter the data to get only the rows that have a
    ''' null ParentID (these are the top-level TreeView items)
    ''' </summary>
    Private Sub AddTopTreeViewNodes(ByVal treeViewData As DataTable)
        Dim view As DataView = New DataView(treeViewData)
        view.RowFilter = "ParentID IS NULL"
        Dim row As DataRowView
        For Each row In view
            Dim NewNode As TreeNode = New TreeNode(row("Subject").ToString(), row("MessageId").ToString())
            TreeView1.Nodes.Add(NewNode)
            AddChildTreeViewNodes(treeViewData, NewNode)
        Next

    End Sub


    ''' <summary>
    ''' Recursively add child TreeView items by filtering by ParentID
    ''' </summary>
    Private Sub AddChildTreeViewNodes(ByVal treeViewData As DataTable, ByVal parentTreeViewNode As TreeNode)
        Dim view As DataView = New DataView(treeViewData)
        view.RowFilter = "ParentID=" + parentTreeViewNode.Value
        Dim row As DataRowView
        For Each row In view
            Dim NewNode As TreeNode = New TreeNode(row("Subject").ToString(), row("MessageId").ToString())
            parentTreeViewNode.ChildNodes.Add(NewNode)
            AddChildTreeViewNodes(treeViewData, NewNode)
        Next
    End Sub


</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
    </style>
    <title>TreeView Database</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <asp:TreeView
        id="TreeView1"
        Runat="server" />


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

The page in Listing 17.26 filters the contents of the Discuss database table by its ParentID column. First, the top-level nodes are added to the TreeView. Next, the child nodes are recursively added to the TreeView with the help of the AddChildTreeViewNodes() method.

Using Populate On Demand and AJAX

You can use the TreeView control even when working with a large set of data. For example, the Microsoft MSDN website (msdn.Microsoft.com) has links to thousands of articles. This website uses a tree view to display the nested links to the articles.

Because thousands of articles are hosted at the MSDN website, not all the tree nodes are downloaded to the browser when you open a page. Instead, additional nodes are downloaded to your browser only when you expand a particular node.

You can use a feature named Populate On Demand with the TreeView control. When you enable the PopulateOnDemand property for a Tree node, child nodes are not added to the parent node until the parent node is expanded.

For example, the page in Listing 17.27 contains an infinitely expanding TreeView. Each time you expand a Tree node, five new child nodes are displayed. Each time you expand a child node, five more child nodes are displayed, and so on (see Figure 17.20).

An infinitely expanding TreeView control.

Figure 17.20. An infinitely expanding TreeView control.

Example 17.27. TreeViewPopulateOnDemand.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">

    Private Sub TreeView1_TreeNodePopulate(ByVal s As Object, ByVal e As TreeNodeEventArgs)
        For i As Integer = 0 To 4
            Dim NewNode As New TreeNode()
            NewNode.Text = String.Format("{0}.{1}", e.Node.Text, i)
            NewNode.PopulateOnDemand = True
            e.Node.ChildNodes.Add(NewNode)
        Next
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>TreeView Populate On Demand</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>

    <%=DateTime.Now.ToString("T") %>


    <hr />


    <asp:TreeView
        ID="TreeView1"
        ExpandDepth="0"
        OnTreeNodePopulate="TreeView1_TreeNodePopulate"
        Runat="server">
        <Nodes>
        <asp:TreeNode
            PopulateOnDemand="true"
            Text="Node 0" />
        </Nodes>
    </asp:TreeView>

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

The TreeView in Listing 17.27 includes a single statically declared TreeNode. Notice that this TreeNode includes a PopulateOnDemand property that is set to the value True.

Additionally, the TreeView control itself includes a TreeNodePopulate event handler. When you expand a TreeNode that has its PopulateOnDemand property enabled, the TreeNodePopulate event handler executes. In the case of Listing 17.27, the event handler adds five new TreeNodes to the TreeNode that was expanded.

When you use the Populate On Demand feature with a modern browser (Internet Explorer 6, Firefox 1, Opera 8), the page containing the TreeView is not posted back to the server when you expand a TreeNode. Instead, the browser uses AJAX (Asynchronous JavaScript and XML) to communicate with the web server. The additional TreeNodes are retrieved from the server, without performing a postback.

The page in Listing 17.27 displays the current time when you open the page. Notice that the time is not updated when you expand a particular TreeNode. The time is not updated because the only content in the page that is updated when you expand a node is the TreeView content. AJAX can have a dramatic impact on performance because it does not require the entire page to be re-rendered each time you expand a TreeNode.

Note

If, for some reason, you don’t want to use AJAX with Populate On Demand, you can assign the value False to the TreeView control’s PopulateNodesFromClient property.

The page in Listing 17.28 contains a more realistic sample of using Populate On Demand and AJAX. This page uses a TreeView control to display the contents of the Discuss database table (see Figure 17.21).

Displaying database data with AJAX.

Figure 17.21. Displaying database data with AJAX.

Example 17.28. TreeViewAJAX.aspx

<%@ Page Language="VB" %>
<%@ Import Namespace="System.Web.Configuration" %>
<%@ Import Namespace="System.Data" %>
<%@ Import Namespace="System.Data.SqlClient" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">


    ''' <summary>
    ''' Only populate the TreeView when the page first loads
    ''' </summary>
    Private Sub Page_Load()
        If Not Page.IsPostBack Then
            PopulateTopNodes()
        End If
    End Sub


    ''' <summary>
    ''' Get the top-level nodes (nodes with a null ParentId)
    ''' </summary>
    Private Sub PopulateTopNodes()
        Dim selectCommand As String = "SELECT MessageId,ParentId,Subject FROM Discuss WHERE ParentId IS NULL"
        Dim conString As String = WebConfigurationManager.ConnectionStrings("Discuss").ConnectionString
        Dim dad As New SqlDataAdapter(selectCommand, conString)
        Dim dtblMessages As New DataTable()
        dad.Fill(dtblMessages)

        For Each row As DataRow In dtblMessages.Rows
            Dim NewNode As New TreeNode(row("Subject").ToString(), row("MessageId").ToString())
            NewNode.PopulateOnDemand = True
            TreeView1.Nodes.Add(NewNode)
        Next
    End Sub


    ''' <summary>
    ''' Get the child nodes of the expanded node
    ''' </summary>
    Protected Sub TreeView1_TreeNodePopulate(ByVal sender As Object, ByVal e As TreeNodeEventArgs)
        Dim selectCommand As String = "SELECT MessageId,ParentId,Subject FROM Discuss WHERE ParentId=@ParentId"
        Dim conString As String = WebConfigurationManager.ConnectionStrings("Discuss").ConnectionString
        Dim dad As New SqlDataAdapter(selectCommand, conString)
        dad.SelectCommand.Parameters.AddWithValue("@ParentId", e.Node.Value)
        Dim dtblMessages As New DataTable()
        dad.Fill(dtblMessages)

        For Each row As DataRow In dtblMessages.Rows
            Dim NewNode As New TreeNode(row("Subject").ToString(), row("MessageId").ToString())
            NewNode.PopulateOnDemand = True
            e.Node.ChildNodes.Add(NewNode)
        Next
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
    </style>
    <title>TreeView AJAX</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <%= DateTime.Now.ToString("T") %>

    <hr />


    <asp:TreeView
        id="TreeView1"
        ExpandDepth="0"
        OnTreeNodePopulate="TreeView1_TreeNodePopulate"
        Runat="server" />


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

When the page in Listing 17.28 first opens, only the first-level message subjects are displayed. These messages are retrieved by the PopulateTopNodes() method.

When you expand a thread, the matching replies are retrieved for the thread. These replies are retrieved in the TreeView1_TreeNodePopulate() event handler.

The TreeView in Listing 17.28 performs well even when working with a large set of data. At any time, only the child messages of a message are retrieved from the database. At no time are all the messages retrieved from the database.

When the page is used with a modern browser, AJAX is used to retrieve the messages from the web server. The page does not need to be posted back to the web server when you expand a particular message thread.

Formatting the TreeView Control

The TreeView control supports an abundance of properties that have an effect on how the TreeView is formatted.

Here are some of the more useful properties of a TreeView control, which modify its appearance (this is not a complete list):

  • CollapseImageToolTipEnables you to specify the title attribute for the collapse image.

  • CollapseImageUrlEnables you to specify a URL to an image for the collapse image.

  • ExpandDepthEnables you to specify the number of TreeNode levels to display initially.

  • ExpandImageToolTipEnables you to specify the title attribute for the expand image.

  • ExpandImageUrlEnables you to specify the URL to an image for the expand image.

  • ImageSetEnables you to specify a set of images to use with the TreeView control.

  • LineImagesFolderEnables you to specify a folder that contains line images.

  • MaxDataBindDepthEnables you to specify the maximum levels of TreeView levels to display when binding to a data source.

  • NodeIndentEnables you to specify the number of pixels to indent a child Tree node.

  • NodeWrapEnables you to specify whether or not text is wrapped in a Tree node.

  • NoExpandImageUrlEnables you to specify the URL to an image for the NoExpand image (typically, an invisible spacer image).

  • ShowCheckBoxesEnables you to display check boxes next to each Tree node. Possible values are All, Leaf, None, Parent, and Root.

  • ShowExpandCollapseEnables you to disable the expand and collapse icons that appear next to each expandable node.

  • ShowLinesEnables you to show connecting lines between Tree nodes.

  • SkipLinkTextEnables you to specify the text used for skipping the contents of the TreeView control. (The Skip Link contains hidden text that is accessible only to users of assistive devices.)

  • TargetEnables you to specify the name of the window that opens when you navigate to a URL with the TreeView control.

The two most interesting properties in this list are the ImageSet and the ShowLines properties. You can set the ImageSet property to any of the following values to modify the images displayed by the TreeView control:

  • Arrows

  • BulletedList

  • BulletedList2

  • BulletedList3

  • BulletedList4

  • Contacts

  • Custom

  • Events

  • Faq

  • Inbox

  • Msdn

  • News

  • Simple

  • Simple2

  • WindowsHelp

  • XPFileExplorer

The ShowLines property causes connecting line images to be rendered between TreeView nodes. Displaying lines between Tree nodes can make it easier to visually discern the nested relationships between nodes. If you want to create custom lines, you can specify a value for the LinesImagesFolder property.

Visual Web Developer Note

Visual Web Developer includes a TreeView Line Image Generator that enables you to create custom connecting lines. You can open this tool in Design view by selecting the TreeView control and opening the Tasks dialog box and selecting Customize Line Images.

The page in Listing 17.29 illustrates how to use both the ImageSet and ShowLines properties (see Figure 17.22).

Formatting a TreeView with an image set and lines.

Figure 17.22. Formatting a TreeView with an image set and lines.

Example 17.29. TreeViewImageSet.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
   "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>TreeView ImageSet</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:TreeView
        id="TreeView1"
        ImageSet="XPFileExplorer"
        ShowLines="true"
        Runat="server">
        <Nodes>
        <asp:TreeNode
            Text="Home">
            <asp:TreeNode Text="Products">
                <asp:TreeNode Text="First Product" />
                <asp:TreeNode Text="Second Product" />
            </asp:TreeNode>
            <asp:TreeNode Text="Services">
                <asp:TreeNode Text="First Service" />
                <asp:TreeNode Text="Second Service" />
            </asp:TreeNode>
        </asp:TreeNode>
        </Nodes>
    </asp:TreeView>


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

The TreeNode object itself also supports several properties that have an effect on the appearance of its containing TreeView. Here is a list of the most useful properties of the TreeNode object:

  • CheckedEnables you to check the check box that appears next to the Tree node.

  • ExpandedEnables you to initially expand a node.

  • ImageToolTipEnables you to associate alt text with a Tree node image.

  • ImageUrlEnables you to specify an image that appears next to a Tree node.

  • NavigateUrlEnables you to specify the URL to which the current Tree node links.

  • SelectActionEnables you to specify the action that occurs when you click a Tree node. Possible values are Expand, None, Select, or SelectExpand.

  • SelectedEnables you to specify whether the current Tree node is selected.

  • ShowCheckBoxEnables you to display a check box for the current Tree node.

  • TargetEnables you to specify the name of the window that opens when you navigate to a URL.

  • ToolTipEnables you to specify a title attribute for the current Tree node.

You can style the TreeView control by attaching Cascading Style Sheet classes to the Style object exposed by the TreeView control. The TreeView control supports the following Style objects:

  • HoverNodeStyleStyle applied to a Tree node when you hover your mouse over a node.

  • LeafNodeStyleStyle applied to leaf Tree nodes (Tree nodes without child nodes).

  • NodeStyleStyle applied to Tree nodes by default.

  • ParentNodeStyleStyle applied to parent nodes (Tree nodes with child nodes).

  • RootNodeStyleStyle applied to root nodes (Tree nodes with no parent nodes).

  • SelectedNodeStyleStyle applied to the selected node.

For example, the page in Listing 17.30 uses several of these Style objects to format a TreeView control (see Figure 17.23).

Using Styles with the TreeView control.

Figure 17.23. Using Styles with the TreeView control.

Example 17.30. TreeViewStyles.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .treeNode
        {
            color:blue;
            font:14px Arial, Sans-Serif;
        }
        .rootNode
        {
            font-size:18px;
            width:100%;
            border-bottom:Solid 1px black;
        }
        .leafNode
        {
            border:Dotted 2px black;
            padding:4px;
            background-color:#eeeeee;
            font-weight:bold;
        }
    </style>
    <title>TreeView Styles</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:TreeView
        id="TreeView1"
        NodeStyle-CssClass="treeNode"
        RootNodeStyle-CssClass="rootNode"
        LeafNodeStyle-CssClass="leafNode"
        Runat="server">
        <Nodes>
        <asp:TreeNode
            Text="Home">
            <asp:TreeNode Text="Products">
                <asp:TreeNode Text="First Product" />
                <asp:TreeNode Text="Second Product" />
            </asp:TreeNode>
            <asp:TreeNode Text="Services">
                <asp:TreeNode Text="First Service" />
                <asp:TreeNode Text="Second Service" />
            </asp:TreeNode>
        </asp:TreeNode>
        </Nodes>
    </asp:TreeView>


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

Furthermore, you can apply styles to particular Tree node levels by taking advantage of the TreeView control’s LevelStyles property. The page in Listing 17.31 uses the LevelStyles property to format first level nodes differently than second level nodes and third level nodes (see Figure 17.24).

Applying styles to different TreeView node levels.

Figure 17.24. Applying styles to different TreeView node levels.

Example 17.31. TreeViewLevelStyles.aspx

<%@ Page Language="VB" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .nodeLevel1
        {
            font:40px Arial,Sans-Serif;
        }
        .nodeLevel2
        {
            font:20px Arial,Sans-Serif;
        }
        .nodeLevel3
        {
            font:10px Arial,Sans-Serif;
        }
    </style>
    <title>TreeView Level Styles</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:TreeView
        id="TreeView1"
        Runat="server">
        <LevelStyles>
        <asp:TreeNodeStyle CssClass="nodeLevel1" />
        <asp:TreeNodeStyle CssClass="nodeLevel2" />
        <asp:TreeNodeStyle CssClass="nodeLevel3" />
        </LevelStyles>
        <Nodes>
        <asp:TreeNode
            Text="Home">
            <asp:TreeNode Text="Products">
                <asp:TreeNode Text="First Product" />
                <asp:TreeNode Text="Second Product" />
            </asp:TreeNode>
            <asp:TreeNode Text="Services">
                <asp:TreeNode Text="First Service" />
                <asp:TreeNode Text="Second Service" />
            </asp:TreeNode>
        </asp:TreeNode>
        </Nodes>
    </asp:TreeView>


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

Building a SQL Hierarchical Data Source Control

In this final section of this chapter, we build a SqlHierarchicalDataSource control. This custom control enables you to declaratively and (thus) easily bind controls such as the Menu and TreeView controls to data retrieved from a database.

Note

The code samples in this section can be found in the SqlHierarchicalDataSourceVB and SqlHierarchicalDataSourceCS applications on the CD.

The page in Listing 17.32 illustrates how you can use the SqlHierarchicalDataSource control to bind a Menu control to a database table that contains nested categories.

Example 17.32. ShowMenu.aspx

<%@ Page Language="VB" %>
<%@ Register TagPrefix="custom" Namespace="AspNetUnleashed" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">

    Sub Menu1_MenuItemClick(sender As Object, e As MenuEventArgs)
        lblSelected.Text = Menu1.SelectedValue
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <style type="text/css">
        .menu
        {
            border:solid 1px black;
            padding:4px;
        }
    </style>
    <title>Show Menu</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:Menu
        id="Menu1"
        DataSourceId="srcCategories"
        OnMenuItemClick="Menu1_MenuItemClick"
        Orientation="Horizontal"
        DynamicMenuStyle-CssClass="menu"
        Runat="server">
        <DataBindings>
            <asp:MenuItemBinding TextField="Name" ValueField="Name" />
        </DataBindings>
    </asp:Menu>


    <custom:SqlHierarchicalDataSource
        id="srcCategories"
        ConnectionString='<%$ ConnectionStrings:Categories %>'
        DataKeyName="CategoryId"
        DataParentKeyName="ParentId"
        SelectCommand="SELECT CategoryId, ParentId, Name FROM Categories"
        Runat="server" />


    <hr />


    <asp:Label
        id="lblSelected"
        Runat="server" />


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

When you open the page in Listing 17.32, all the rows from the Categories table are displayed in the Menu control.

Notice that the SqlHierarchicalDataSource control includes two properties: DataKeyName and DataParentKeyName. The DataKeyName property represents the name of a database column that contains a unique value for each database table row. The DataParentKeyName column represents the name of a database column that relates each row to its parent row.

Furthermore, notice that the Menu control includes a MenuItemBinding, which associates the database Name column with the Menu item Text property, and the Name column with the Menu item Value property.

You also can use the SqlHierarchicalDataSource control when working with the TreeView control. The page in Listing 17.33 displays all the rows from the Discuss database table in a TreeView control.

Example 17.33. ShowTreeView.aspx

<%@ Page Language="VB" %>
<%@ Register TagPrefix="custom" Namespace="AspNetUnleashed" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
 "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">


    Sub TreeView1_SelectedNodeChanged(sender As object, e As EventArgs)
        lblSelected.Text = TreeView1.SelectedValue
    End Sub
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head id="Head1" runat="server">
    <title>Show TreeView</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>


    <asp:TreeView
        id="TreeView1"
        DataSourceID="srcDiscuss"
        OnSelectedNodeChanged="TreeView1_SelectedNodeChanged"
        ImageSet="News"
        Runat="server">
        <DataBindings>
            <asp:TreeNodeBinding
                TextField="Subject"
                ValueField="MessageId" />
        </DataBindings>
    </asp:TreeView>

    <custom:SqlHierarchicalDataSource
        id="srcDiscuss"
        ConnectionString='<%$ ConnectionStrings:Discuss %>'
        DataKeyName="MessageId"
        DataParentKeyName="ParentId"
        SelectCommand="SELECT MessageId,ParentId,Subject FROM Discuss"
        Runat="server" />


    <hr />


    You selected message number:
    <asp:Label
        id="lblSelected"
        Runat="server" />


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

When you open the page in Listing 17.33, the contents of the Discuss database table are displayed in the TreeView control.

All the code for the SqlHierarchicalDataSource control is included on the CD that accompanies this book. The control is composed out of five separate classes:

  • SqlHierarchicalDataSourceThis class represents the actual control. It inherits from the base SqlDataSource control and implements the IHierarchicalDataSource interface.

  • SqlHierarchicalDataSourceViewThis class represents the hierarchical data returned by the control. It inherits from the base HierarchicalDataSourceView class.

  • SqlHierarchicalEnumerableThis class represents a collection of SqlNodes.

  • SqlNodeThis class represents a particular database row from the data source. It includes methods for retrieving child and parent rows.

  • SqlNodePropertyDescriptorThis class inherits from the base PropertyDescriptor class. It converts the database columns represented by a SqlNode into class properties so that you can bind to the columns using TreeView and Menu control DataBindings.

Note

The Microsoft .NET Framework SDK Documentation includes a sample of a FileSystemDataSource control that implements the IHiearchicalDataSource interface. Look up the IHearchicalDataSource topic in the documentation index.

Summary

In this chapter, you learned how to use the SiteMapPath, Menu, and TreeView Controls. First, you learned how to use the SiteMapPath control to display a breadcrumb trail. You learned how to format the SiteMapPath control with styles and templates.

Next, you explored the Menu control. You learned how to create both vertical and horizontal menus. You also learned how you can bind a Menu control to different data sources such as Site Maps, XML documents, and database data.

The TreeView control was also discussed. You learned how to display check boxes with a TreeView control. You also learned how to bind a TreeView control to different data sources such as Site Maps, XML documents, and database data. You also learned how to display a large set of Tree nodes efficiently by using AJAX and the TreeView control.

Finally, we created a custom SqlHierarchicalDataSource control that enables you to easily bind controls such as the Menu and TreeView controls to hierarchical database data.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset