April 11, 2010 by Christoff Truter C# ASP.NET
Some time ago I wrote a post on populating a treeview control within
windows forms. The
same method (slightly altered) can be used to populate a treeview control in asp.net,
even though its not quite what microsoft put in place with regards to binding
hierarchical data.
One of these mechanisms (that they put in place) are the XmlDataSource control - which we can use to bind
hierarchical data to a treeview control, lets have a quick look.
The xml we're going to use will look something like this:
<?xml version="1.0" encoding="utf-8" ?> <nodes title="Programming Languages"> <node title="Microsoft"> <node title="C#"> <node title="LinQ"></node> </node> <node title="VB.net"></node> </node> <node title="Open Source"> <node title="Python"></node> <node title="Ruby"></node> <node title="PHP"> <node title="5.2"></node> <node title="4.4"></node> </node> <node title="Perl"></node> <node title="Java"></node> </node> </nodes>
<asp:TreeView ID="tree" runat="server" DataSourceID="source" ExpandDepth="0"> <DataBindings> <asp:TreeNodeBinding DataMember="node" TextField="title" /> <asp:TreeNodeBinding DataMember="nodes" TextField="title" /> </DataBindings> </asp:TreeView> <asp:XmlDataSource ID="source" runat="server" DataFile="~/xml/programming.xml"> </asp:XmlDataSource>
public class HierarchicalObjectDataSource : ObjectDataSource, IHierarchicalDataSource { public event EventHandler DataSourceChanged; public String DataTextField { get; set; } public String DataValueField { get; set; } public String DataParentField { get; set; } public HierarchicalDataSourceView GetHierarchicalView(string viewPath) { return new HierarchicalObjectDataSourceView(this, viewPath); } }
public class Hierarchical : IHierarchyData { public HierarchicalCollection source { get; set; } public Int32 Value { get; set; } public Int32 ParentID { get; set; } public String Text { get; set; } private Hierarchical() { } public Hierarchical(int value, int parentID, string text) { this.Value = value; this.ParentID = parentID; this.Text = text; } public IHierarchicalEnumerable GetChildren() { HierarchicalCollection children = new HierarchicalCollection(); foreach (Hierarchical Hierarchical in this.source) { if (Hierarchical.ParentID == this.Value) { children.Add(Hierarchical); } } return children; } public IHierarchyData GetParent() { foreach (Hierarchical Hierarchical in this.source) { if (Hierarchical.Value == this.ParentID) return Hierarchical; } return null; } public bool HasChildren { get { HierarchicalCollection children = GetChildren() as HierarchicalCollection; return children.Count > 0; } } public object Item { get { return this; } } public string Path { get { return this.Value.ToString(); } } public string Type { get { return this.GetType().ToString(); } } public override string ToString() { return this.Text; } }
public class HierarchicalCollection : List<Hierarchical>, IHierarchicalEnumerable { public HierarchicalCollection() : base() { } public IHierarchyData GetHierarchyData(object enumeratedItem) { return enumeratedItem as IHierarchyData; } }
public class HierarchicalObjectDataSourceView : HierarchicalDataSourceView { private string _viewPath; private HierarchicalCollection _source = new HierarchicalCollection(); public HierarchicalObjectDataSourceView(HierarchicalObjectDataSource source, string viewPath) { _viewPath = viewPath; CreateCollection(source); } private void CreateCollection(HierarchicalObjectDataSource source) { IEnumerable data = source.Select(); if (data != null) { foreach (Object dataItem in data) { Int32 value = Convert.ToInt32(DataBinder.GetPropertyValue(dataItem, source.DataValueField, null)); Int32 parentID = Convert.ToInt32(DataBinder.GetPropertyValue(dataItem, source.DataParentField, null)); String text = DataBinder.GetPropertyValue(dataItem, source.DataTextField, null); _source.Add(new Hierarchical(value, parentID, text)); } } } public override IHierarchicalEnumerable Select() { HierarchicalCollection collection = new HierarchicalCollection(); Int32 ParentId = (!String.IsNullOrEmpty(_viewPath)) ? Convert.ToInt32(_viewPath) : 0; foreach (Hierarchical Hierarchical in this._source) { if (Hierarchical.ParentID == ParentId) { Hierarchical.source = _source; collection.Add(Hierarchical); } } return collection; } }
<asp:TreeView ID="tree" runat="server" DataSourceID="source" ExpandDepth="0"> </asp:TreeView> <asp:HierarchicalObjectDataSource ID="source" runat="server" SelectMethod="GetData" TypeName="CSTruter.com.Data" DataParentField="ParentID" DataValueField="Value" DataTextField="Text" />
August 27, 2009
Developer February 29, 2012 by Craig
Hi Mr. Truter, This is fantastic code. I have implemented a version of this in my own project and it all works nicely. I am currently trying to solve one issue: I receive an (int)ID back from the database which represents the ID of a node somewhere in my tree (could be any depth level) 1. How do I find the node in the tree which matches my ID (I'm trying to use LINQ: TreeNode selectedNode = this.myTreeOnPage.Nodes.OfType<TreeNode>().FirstOrDefault(node => node.DataPath == Convert.ToString(TreeIDFromDB)) but am also considering a good old foreach loop instead. 2. How do I expand only the parent nodes in the path to the selected node? Any suggestions you can provide is greatly appreciated! Thanks, Craig