Introduction
This quick tutorial will hit on the major features of the IHierarchicalDataSource
provided by ASP.NET 2.0. Throughout I take a common set of data (a storefront listing of categories) in the form of a strongly typed generic list and entity and bind it together using the IHierarchy
family of interfaces demonstrating how to turn any custom collection into a useful data binding tool.
Background
Displaying hierarchical data on the web is not a simple task, as you may already know if you have ever tried to bind a custom collection of hierarchical data to a standard ASP.NET TreeView
control. No matter what the original shape of the data is, it is quite a pain to loop through and bind using the AddNode
methods provided. You have to recursively look up the parent controls, ensure your data is sorted, etc. Overall it is a pretty big pain in the [Insert Bleep Here]! Hopefully after reviewing the following, you will find it much easier to extend your custom collections with this technology and remove all your nested data headaches!
Enjoy!
Using the code
I have tried to package this up as seamless as possible. Open'er up in Visual Studio 2005 and you should have a file path ASP.NET Web Site. I have one file for each class object (I guess that is the "team developer" in me) and a static
method in the common class for quick sample data tucked nicely into a strongly typed generic list implementation.
Viewing the Default.aspx page should yield a tree view of a computer store product category TreeView
demonstrating the code below.
On with the show...
To start with, we need a basic entity and collection, mine looks similar to this:
using System;
using System.Collections.Generic;
public class Category {
private int _categoryId;
private int _parentId;
private string _name;
public int CategoryId {
get { return _categoryId; }
set { _categoryId = value; }
}
public int ParentId {
get { return _parentId; }
set { _parentId = value; }
}
public string Name {
get { return _name; }
set { _name = value; }
}
public Category(int categoryId, int parentId, string name) {
_categoryId = categoryId;
_parentId = parentId;
_name = name;
}
}
public class CategoryCollection : List<Category> {
public CategoryCollection()
: base() {
}
}
Implementing IHierarchyData on the Entity
In order to tell the CLR that your collection has hierarchical data, it in fact must be! Let's add that by adding the System.Web.UI
namespace along with implementing the IHierarchyData
interface and its required members as shown here:
using System;
using System.Collections.Generic;
using System.Web.UI;
public class Category : IHierarchyData {
...
#region IHierarchyData Members
public IHierarchicalEnumerable GetChildren() {
CategoryCollection children = new CategoryCollection();
foreach (Category category in Common.GetCategoryData()) {
if (category.ParentId == this.CategoryId) {
children.Add(category);
}
}
return children;
}
public IHierarchyData GetParent() {
foreach (Category category in Common.GetCategoryData()) {
if (category.CategoryId == this.ParentId)
return category;
}
return null;
}
public bool HasChildren {
get {
CategoryCollection children = GetChildren() as CategoryCollection;
return children.Count > 0;
}
}
public object Item {
get { return this; }
}
public string Path {
get { return this.CategoryId.ToString(); }
}
public string Type {
get { return this.GetType().ToString(); }
}
#endregion
}
The GetChildren()
and GetParent()
methods are where the magic really takes place. These two internal methods power the hierarchy definition and allow the controls to link them appropriately.
Implementing IHierarchicalEnumerable on the Collection
For the code immediately above to work, the method GetChildren()
is counting on us handing back an implementation of IHierarchicalEnumerable
.
Implementing this interface is a simple task of coding one method (GetHierarchyData()
) that will ensure proper object typing within the collection as shown below:
public class CategoryCollection : List<Category>, IHierarchicalEnumerable {
...
#region IHierarchicalEnumerable Members
public IHierarchyData GetHierarchyData(object enumeratedItem) {
return enumeratedItem as IHierarchyData;
}
#endregion
}
Finally... Some Output!
To see the results, simply create a new ASPX page and add a ASP:TreeView
control to it. In code-behind, the following snippets will bind the results from your newly decorated collection to the tree view and organize it within the hierarchy you defined.
ASP.Net
----------------------------------------------------------
<asp:TreeView ID="uxTreeView" runat="server" />
Code Behind
----------------------------------------------------------
protected void Page_Load(object sender, EventArgs e) {
if (!IsPostBack) {
CategoryCollection collection = Common.GetRootCategories();
uxTreeView.DataSource = collection;
uxTreeView.DataBind();
}
}
Now that your collection and entity are all hyped-up on interfaces, you can use them again and again on hierarchy displaying controls natively.
Points of Interest
If anyone can answer the question as to why this is hidden away in the System.Web.UI
namespace, I would love to hear it! I cannot imagine this having "web only" requirements, but I have not yet tried it in a Windows application.
In the code download, I have also included an implementation of IHierarchicalDataSource
and HierarchicalDataSourceView
for those of you who prefer to declaratively bind the data on the ASPX side with DataSource
controls.
History
- Wednesday, July 18, 2007 - Initial version