6 Apr
2008

ASP.Net HierarchicalDataSource<T>

Category:UncategorizedTag: , , :

The Asp.net 2.0 tree control, as well as many 3rd party controls binds to hierarchical data via an IHierarchicalDataSource interface. Asp.net provides an implementation OOTB with the HierarchicalDataSourceControl! Easy, let?s hook that up to our? wait this control only takes data in xml format or from a sitemap? Hmm, we don?t want to convert our model to xml, and a sitemap seems inappropriate. We spend a lot time doing great patterns such as MVP & MVC, we should just be able to bind up a list of model objects we already have.

Good thing MS has exposed a set of interfaces and abstract classes in System.Web.UI for us to implement our own IHierarchicalDataSource and HierarchicalDataSourceView and IHierarchicalEnumerable and then IHierarchyData… geesh.

Data? So let’s see here, in order to bind our model to the tree control it needs to implement an interface in System.Web.UI? Well that’s just not going to happen, so its time for some Elegant Code.

Story:

Dude, as a software developer, needs to create a custom implementation of IHierarchicalDataSource, and the rest of its parts, so that he can bind a list of objects to a tree control in asp.net

  • Use existing model to bind to tree control
  • Must be able to reuse data source for future models
  • Model must not contain a reference to System.Web.UI

In order to setup our model to address the acceptance criteria we are going to use an interface with a self-referencing generic declaration, where the type will specify itself as the concrete type. This will let us create a nice generic hierarchical model to pass into our datasource without resorting to any sort of base class.

namespace POC.Common
{
    public interface IModelWithHierarchy<T>
    {
        string Name { get; set; }
        T Parent { get; set; }
        List<T> Children { get; set; }
    }
}

Lets note that we have placed the interface in a Common namespace which represents a shared.dll between Web & Model

The UI part of criteria is now a bit more tricky because the HierarchicalDataSourceView expects a IHierarchicalEnumerable datasource which contains IHierarchyData. Said IHierarchyData != IModelWithHierarchy<T>.  Luckily someone else has already figured this one out for us. We need an adapter.

image

To instantiate our HierarchyData adapter objects we will use an extension method and linq ‘Select’ to convert our datasource IEnumerable<T> of IModelWithHierarchy<T> ‘s to an IHierarchicalEnumerable of IHierarchyData.

namespace POC.Web.HierarchyExtensions
{
    public static class HierarchyConverter
    {
        public static HierarchicalModelList
            ToHierarchicalModelList<T>(this IEnumerable<T> modelWithHierarchy)
            where T : IModelWithHierarchy<T>
        {
            return new HierarchicalModelList(
                modelWithHierarchy.Select(m => new HierarchyData<T>(m) as IHierarchyData));
        }
    }
}

I am not going to bore you with the implementation details of the HierarachyData<T> adapter and the .net abstractions, but have dropped the source code here if your interested. The end result:

TreeView1.DataSource = new HierarchicalModelDataSource<Category> { DataSource = Categories };
TreeView1.DataBind();
TreeView1.CollapseAll();

Story complete!