Now that we have understood the theory behind the TreeView controls, let us look at the following examples.
- How to use the TreeView control to display site navigation structure
- How to implement TreeView data binding with an XML file
- How to dynamically populate nodes in a TreeView control
- How to perform XSL transformation on XML data before displaying that information through a TreeView control
Let us start our implementation by discussing the first example in the above list.
Using the TreeView Control to Display Site Navigation Structure
In this example, we will use the TreeView control to display hierarchical information about the site structure using the contents of the web.sitemap file. In the web.sitemap file, you specify the list of nodes that specify the navigation structure of the site, which can be completely independent of the site folder layout or other structure. When a SiteMapDataSource is placed on the page, it will specifically look for a file with that name and then read the contents of the web.sitemap file and consume that information. Once the information is available in the data source control, you can then bind a TreeView control to the data source control to display that information in the web page.
Fire up Visual Studio 2005 and create a new ASP.NET Web Site named TreeView by selecting New Web Site from the File menu. In the New Web Site dialog box, click the Browse button and select Local IIS as the location and click Open. In the New Web Site dialog box, enter http://localhost/MyProjects/15Seconds/TreeView as the location of the web site. Then click OK.
Once the project is created, add a web.sitemap file by selecting Add New Item from the Web Site menu. In the Add New Item dialog box, select Site Map and click Add. This will result in a new file named web.sitemap being added to the web site.
Modify the code in the web.sitemap file to look as shown below.
<?xmlversion="1.0" encoding="utf-8"
?>
<siteMap>
<siteMapNodetitle="Home" url="~/default.aspx" >
<siteMapNodetitle="Introduction
to ASP.NET"
url="~/introduction/default.aspx">
<siteMapNodetitle="What's
New in Whidbey?"
url="~/introduction/whatsnew.aspx"/>
<siteMapNodetitle="Introduction
to Visual Web Developer"
url="~/introduction/vwd.aspx"/>
</siteMapNode>
<siteMapNodetitle="Building
A Web Application"
url="~/development/default.aspx">
<siteMapNodetitle="Building
a Simple Application"
url="~/development/simple/default.aspx">
<siteMapNodetitle="Sharing
Code Between Pages"
url="~/development/simple/codedirectory.aspx"/>
</siteMapNode>
</siteMapNode>
</siteMapNode>
</siteMap>
Now that we have the web.sitemap file created, let us create a new ASP.NET Web Form and name it as SiteNavigation.aspx. To the newly added web form, add a TreeView and SiteMapDataSource controls to it. Set the ExpandImageUrl and CollapseImageUrl properties of the TreeView control to "Images/closed.gif" and "Images/open.gif" respectively. Then set the DataSourceID property of the TreeView to the ID of the SiteMapDataSource control we added earlier. After modification, the code should look like the following.
<%@ PageLanguage="C#"%>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.1//EN""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml">
<headrunat="server">
<title>Untitled Page</title>
</head>
<body>
<formid="form1"runat="server">
<div>
<asp:TreeViewDataSourceID="SiteMapDataSource1"
ExpandImageUrl="Images/closed.gif"
CollapseImageUrl="Images/open.gif"ID="TreeView1"
Runat="server">
</asp:TreeView>
</div>
<div>
<asp:SiteMapDataSourceID="SiteMapDataSource1"Runat="server">
</asp:SiteMapDataSource>
</div>
</form>
</body>
</html>
When you execute the above code, you will see an output that is somewhat similar to the following screenshot.

The advantage of using the TreeView control with a SiteMapDataSource is that Web site navigation information can be maintained in a central location. The default provider for the SiteMapDataSource control is the XmlSiteMapProvider, which retrieves site navigation information from the web.sitemap file. Note that the web.sitemap file must always appear in the root directory of your ASP.NET application.
Implementing TreeView Data Binding with an XML File
In this example, we will bind the TreeView control to an XML file. To accomplish this, you need to go through the following two steps.
- Add an XmlDataSource control to the page and set its DataFile property to the name of the XML File
- Then add a TreeView control and set its DataSourceID property to the ID of the XmlDataSource control.
- Then map the nodes and their attributes in the XML file to the TreeView nodes by declaring the asp:TreeNodeBinding elements as part of the TreeView declaration.
For the purposes of this example, let us create an XML file named Categories.xml that looks like the following.
<?xmlversion='1.0'?>
<!-- This file represents
a fragment of a Categories inventory database -->
<Categories>
<CategoryID="1" Name="Beverages">
<DescriptionValue="Soft
drinks, coffees, teas, beers, and ales"/>
</Category>
<CategoryID="2" Name="Condiments">
<DescriptionValue="Sweet
and savory sauces, relishes, spreads, and
seasonings"/>
</Category>
<CategoryID="3" Name="Confections">
<DescriptionValue="Desserts,
candies, and sweet breads"/>
</Category>
<CategoryID="4" Name="Dairy Products">
<DescriptionValue="Cheeses"/>
</Category>
</Categories>
Once the XML file is created, create a new Web Form named TreeViewDataBinding.aspx and modify its code to look like the following.
<%@ PageLanguage="C#"%>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.1//EN""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml">
<headrunat="server">
<title> Binding TreeView Control with an XML File</title>
</head>
<body>
<formid="form1"runat="server">
<div>
<asp:TreeViewExpandImageUrl="Images/closed.gif"
CollapseImageUrl="Images/open.gif"ID="TreeView1"
Runat="server"DataSourceID="XmlDataSource1">
<DataBindings>
<asp:TreeNodeBindingDataMember="Category"
ValueField="ID"TextField="Name">
</asp:TreeNodeBinding>
<asp:TreeNodeBindingDataMember="Description"
ValueField="Value"
TextField="Value">
</asp:TreeNodeBinding>
</DataBindings>
</asp:TreeView>
</div>
<div>
<asp:XmlDataSourceID="XmlDataSource1"Runat="server"
DataFile="~/Data/Categories.xml">
</asp:XmlDataSource>
</div>
</form>
</body>
</html>
The above code listing contains a TreeView control that is bound to an XML file through an XmlDataSource control. This is accomplished by setting the DataSourceID property of the TreeView control to the XmlDataSource control. The TreeView associates properties of individual TreeNode objects to attributes of XML nodes in the hierarchy. When you perform data binding, attributes in the individual XML elements are promoted to properties of the data item. Also note that the TreeView hierarchy exactly matches the hierarchy of the source XML. Because of this, you normally construct the XML specifically for binding to the TreeView.
Executing the above code results in the following output.

Now that we have understood how to statically bind an XML file to a TreeView control, let us now understand the steps involved in dynamically populating the treeview control with contents from a database.
Dynamically Populating Nodes in the TreeView
In this section, you will dynamically populate the nodes in the TreeView with data from the database. The first level of nodes will represent master data — in this case, authors. When users click a node, the child nodes for that author will be created by making a query to the database that fetches all the titles for that particular author. For this example, let us create a new web form named DynamicTreeView.aspx and modify its code to look like as shown below.
<%@ PageLanguage="C#"%>
<%@ ImportNamespace="System.Data"%>
<%@ ImportNamespace="System.Data.SqlClient"%>
<%@ ImportNamespace="System.Configuration"%>
<!DOCTYPEhtmlPUBLIC"-//W3C//DTD XHTML 1.1//EN""http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<htmlxmlns="http://www.w3.org/1999/xhtml">
<headrunat="server">
<title>Dynamic Population of the TreeView
Control</title>
<scriptrunat=server>
void Node_Populate(object
sender,
System.Web.UI.WebControls.TreeNodeEventArgs e)
{
if(e.Node.ChildNodes.Count == 0)
{
switch( e.Node.Depth )
{
case 0:
FillAuthors(e.Node);
break;
case 1:
FillTitlesForAuthors(e.Node);
break;
}
}
}
void
FillAuthors(TreeNode node)
{
string connString = System.Configuration.ConfigurationSettings.
ConnectionStrings["NorthwindConnnection"].ConnectionString;
SqlConnection connection = new SqlConnection(connString);
SqlCommand command = new SqlCommand("Select * From
authors",connection);
SqlDataAdapter adapter = new SqlDataAdapter(command);
DataSet authors = new DataSet();
adapter.Fill(authors);
if
(authors.Tables.Count > 0)
{
foreach (DataRow row in authors.Tables[0].Rows)
{
TreeNode newNode = new
TreeNode(row["au_fname"].ToString() +
" " +
row["au_lname"].ToString(),
row["au_id"].ToString());
newNode.PopulateOnDemand = true;
newNode.SelectAction = TreeNodeSelectAction.Expand;
node.ChildNodes.Add(newNode);
}
}
}
void
FillTitlesForAuthors(TreeNode node)
{
string
authorID = node.Value;
string connString = System.Configuration.ConfigurationSettings.
ConnectionStrings["NorthwindConnnection"].ConnectionString;
SqlConnection connection = new SqlConnection(connString);
SqlCommand command = new SqlCommand("Select T.title,
T.title_id
From titles T" +
" Inner
Join titleauthor TA on
T.title_id =
TA.title_id " +
" Where TA.au_id = '" + authorID + "'", connection);
SqlDataAdapter adapter = new SqlDataAdapter(command);
DataSet titlesForAuthors = new DataSet();
adapter.Fill(titlesForAuthors);
if
(titlesForAuthors.Tables.Count > 0)
{
foreach (DataRow row in
titlesForAuthors.Tables[0].Rows)
{
TreeNode newNode = new TreeNode(
row["title"].ToString(),
row["title_id"].ToString());
newNode.PopulateOnDemand = false;
newNode.SelectAction = TreeNodeSelectAction.None;
node.ChildNodes.Add(newNode);
}
}
}
</script>
</head>
<body>
<formid="form1"runat="server">
<div>
<asp:TreeViewRunat="Server"ExpandImageUrl="Images/closed.gif"
CollapseImageUrl="Images/open.gif"
OnTreeNodePopulate="Node_Populate"ID="tvwauthors">
<Nodes>
<asp:TreeNodeText="Authors"PopulateOnDemand=true
Value="0"/>
</Nodes>
</asp:TreeView>
</div>
</form>
</body>
</html>
The above code consists of two utility methods named FillAuthors and FillTitlesForAuthors, which are used to retrieve the list of authors and the list of titles for a specific author respectively. The FillAuthors method starts by retrieving the connection string from the web.config file by invoking the ConnectionString property of the ConnectionStringSettings class. The connection string is defined in the web.config as shown below.
<connectionStrings>
<addname="NorthwindConnnection"
connectionString="server=localhost;database=Pubs;uid=
sa;pwd=test"/>
</connectionStrings>
Once the connection string is retrieved, it then creates an instance of the SqlConnection object passing in the connection string as an argument to its constructor. After that it creates SqlCommand, SqlDataAdapter, and DataSet objects. Then it fills the DataSet object with the results of the sql query execution by invoking the Fill method of the DataSet object. Then the code loops through all the rows contained in the DataTable adding them one at a time to the TreeView control. The implementation of the FillTitlesForAuthors is very similar to the FillAuthors method except that it executes a different query in this case. While constructing the query, it also uses the author id value that is retrieved from the currently selected node.
Now that we have had a look at the code for the methods, let us look at the declaration of the TreeView control. The TreeView control associates the OnTreeNodePopulate method with an event handler named Node_Populate. The Node_Populate method simply checks the depth of the node and it is 0, it invokes the FillAuthors method and if it is 1, it invokes the FillTitlesForAuthors method. As part of the TreeView declaration, we also set the PopulateOnDemand property of the asp:TreeNode element to true. This property allows you to indicate that the node will be populated dynamically through the code.
If you execute the above code, you will see the following output.

Transforming XML Data and Displaying that Information in a TreeView Control
It is also possible for you to transform the XML data before it is displayed by the TreeView control. You can do this by setting the TransformFile property of the XmlDataSource control. This is very useful in scenarios when the original XML structure is not suitable for display through the TreeView control. In that case, you can transform the XML data using XSL and then bind that transformed XML to the TreeView control.
As with the XML data, you typically load the style sheet from a file, indicated by the TransformFile property, but you can also use it in string form directly using the Transform property.
For the purposes of this example, we will use the Categories.xml file that we used in our previous example. We will transform the categories.xml file using a Stylesheet named categories.xsl. Code for the categories.xsl file is shown below.
<xsl:stylesheetversion="1.0" xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
<xsl:templatematch="/">
<categories-list>
<xsl:for-eachselect="//Categories/Category">
<category>
<xsl:attributename="id">
<xsl:value-ofselect="@ID"/>
</xsl:attribute>
<xsl:attributename="name">
<xsl:value-ofselect="@Name"/>
</xsl:attribute>
<xsl:elementname="desc">
<xsl:attributename="value">
<xsl:value-ofselect="Description/@Value"/>
</xsl:attribute>
</xsl:element>
</category>
</xsl:for-each>
</categories-list>
</xsl:template>
</xsl:stylesheet>
Now that we have created the XSL, let us create a new page that exercises the above XSL. To this end, create a new page named TreeViewXmlTransformation.aspx and modify its code to look like the following.
<%@ PageLanguage="C#"%>
<htmlxmlns="http://www.w3.org/1999/xhtml">
<headid="Head1"runat="server">
<title>XML Transformation</title>
</head>
<body>
<formid="form1"runat="server">
<div>
<asp:TreeViewID="TreeView1"Runat="server"
ExpandImageUrl="Images/closed.gif"
CollapseImageUrl="Images/open.gif"
DataSourceID="XmlDataSource1">
<DataBindings>
<asp:TreeNodeBindingDataMember="category"
ValueField="id"TextField="name">
</asp:TreeNodeBinding>
<asp:TreeNodeBindingDataMember="desc"
ValueField="value"TextField="value">
</asp:TreeNodeBinding>
</DataBindings>
</asp:TreeView>
<asp:XmlDataSourceID="XmlDataSource1"Runat="server"
DataFile="~/Data/Categories.xml"
TransformFile="~/Data/Categories.xsl"/>
</div>
</form>
</body>
</html>
As you can see from the above code, the ValueField and TextField attributes of the asp:TreeNodeBinding element are set to the new XML element names that are produced by the XML. If you execute the above code, you will see an output that is somewhat similar to the following screenshot.

As you can see from the above screenshot, the root node is shown as categories-list, which is produced as a direct result of the XSL transformation.