If you've used the beta version of ASP.NET 2.0 a little, the Menu and TreeView controls in particular, you may have noticed that the datasources they consume are different from those that GridView or FormView use. But of course, Menu and TreeView have to use hierarchical data sources, whereas other controls use tabular data sources.
Tabular data sources that you get out of the box are mainly SqlDataSource and ObjectDataSource. Of course, you can also build your own data source (more on this in later posts). The nice thing is that with ObjectDataSource, you can potentially get data from any data store.
Now, for hierarchical data sources, you've got XmlDataSource and you've got SiteMapDataSource, and... and that's it. So if you want to populate a Menu or TreeView from a database, you'll pretty much have to do it from code.
Enter CompositeHierarchicalDataSource... This control I've developed on my free time (which is mainly composed of an aggregation of my serious work's compilation time) composes several tabular data sources into one hierarchical data source using relations.
Here's a simple page that displays a menu that takes its data from a composition of one ObjectDataSource and two AccessDataSources:
<%@ Page Language="C#" debug="true" %>
<%@ Register Namespace=MyControls.DataSources.CompositeHierarchicalDataSource TagPrefix=my %>
<!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">
<form id="form1" runat="server">
<my:CompositeHierarchicalDataSource runat=server ID=Composite1 RootViewName="Categories:DefaultView">
<asp:ObjectDataSource ID="Categories" Runat="server" TypeName="Categories"
<asp:AccessDataSource ID="SubCategories" Runat="server" DataFile="~/data/things.mdb"
SelectCommand="SELECT [Id], [CategoryId], [Name] FROM [SubCategories]"/>
<asp:AccessDataSource ID="Things" Runat="server" DataFile="~/data/things.mdb"
SelectCommand="SELECT [Id], [SubCategoryId], [Name], [Description], [Url] FROM [Things]"/>
<my:Relation ParentDataSourceId="Categories" ParentView="DefaultView" ParentColumns="value"
ChildDataSourceId="SubCategories" ChildView="DefaultView" ChildColumns="CategoryId"/>
<my:Relation ParentDataSourceId="SubCategories" ParentView="DefaultView" ParentColumns="Id"
ChildDataSourceId="Things" ChildView="DefaultView" ChildColumns="SubCategoryId"/>
<asp:Menu Runat=Server ID=myMenu DataSourceID=Composite1>
<asp:MenuItemBinding DataMember="Categories:DefaultView" TextField="text" ValueField="value" />
<asp:MenuItemBinding DataMember="SubCategories:DefaultView" TextField="Name" ValueField="Id" />
<asp:MenuItemBinding DataMember="Things:DefaultView" TextField="Name" ValueField="Id"
ToolTipField="Description" NavigateUrlField="Url" />
The nice thing is that you can in principle use any tabular data source to build your hierarchical data source. In principle only: this is still a proof of concept and is currently limited to SqlDataSources, ObjectDataSources whose views return DataViews, and datasources whose views implement ITabularDataSourceView. Another problem it currently has is that it loads all of the data at one time. It would be nice to have lazy loading for populate on demand TreeView scenarios.
It's shared source, so you're free to use and modify the code as you wish. Enjoy!
In future posts, I'll explain how it works in details, which should make a nice tutorial on how to develop your own hierarchical data source (hint of other missing data sources: LdapDataSource, FileSystemDataSource).
GotDotNet CodePlex workspace for this data source can be found here: