Click here to Skip to main content
Click here to Skip to main content

Binding the ASP.NET TreeView to a DataSet or an ObjectDataSource

By , 1 May 2008
 

Introduction

The TreeView in ASP.NET is a powerful control that helps display hierarchical data. However, unlike other controls, it does not support binding to a DataSet or an ObjectDataSource. I have seen a lot of developers do this the old fashioned way, filling the tree programmatically, which is a waste of time and energy.

The solution

The key to this solution is that the TreeView can bind to any object implementing the interface IHierarchicalDataSource. So, this article presents to you a small class that will take a DataSet as an input and return an object that implements IHierarchicalDataSource so that the TreeView can easily bind with your DataSets.

Under the hood

The class HierarchicalDataSet presents data in a hierarchy, which means supports Parent-Child relationships, just like the nature of a TreeView control. You have nodes, and under some nodes, you have children. Creating this structure in a database involves having a table reference itself to implement the parent-child relationship. Here is how such a table would look like:

Table

Here is a quick example for some records to see how they will present the child parent relationship:

DataRow row = dataSet.Tables[0].NewRow();
row["ID"] = 1;
row["Text"] = "Parent 1";
dataSet.Tables[0].Rows.Add(row);

row = dataSet.Tables[0].NewRow();
row["ID"] = 2;
row["Text"] = "Parent 2";
dataSet.Tables[0].Rows.Add(row);

row = dataSet.Tables[0].NewRow();
row["ID"] = 3;
row["ParentID"] = 1;
row["Text"] = "Child 1";
dataSet.Tables[0].Rows.Add(row);

row = dataSet.Tables[0].NewRow();
row["ID"] = 4;
row["ParentID"] = 1;
row["Text"] = "Child 2";
dataSet.Tables[0].Rows.Add(row);

row = dataSet.Tables[0].NewRow();
row["ID"] = 5;
row["ParentID"] = 2;
row["Text"] = "Child 3";
dataSet.Tables[0].Rows.Add(row);

row = dataSet.Tables[0].NewRow();
row["ID"] = 6;
row["ParentID"] = 2;
row["Text"] = "Child 4";
dataSet.Tables[0].Rows.Add(row);

Using the code

Using the code is very simple. You need to call the constructor of the class that takes the DataSet and the two column names needed. The primary key and the foreign key reference the same table.

TreeView1.DataSource = new HierarchicalDataSet(dataSet, "ID", "ParentID");

The original blog of this article can be found here.

Hope this helps.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Ralph Varjabedian
Chief Technology Officer Xplorium
Lebanon Lebanon
Member
No Biography provided

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5memberD-Kishore4 Sep '12 - 18:44 
Great
GeneralMy vote of 5membershrikant.sherekar3 May '12 - 22:07 
This is really great article. Thanks a lot for solving the recursive method loading treeview issues. I appreciate your efforts and good knowledge.
GeneralMy vote of 5membermanoj kumar choubey16 Feb '12 - 0:40 
Nice
GeneralGreat Article, but what if I have checkboxes in my tree view by having this ShowCheckBoxes="All"memberrperetz12 Feb '10 - 9:19 
I have check boxes in my tree view, so I have one more field in my dataset for is_selected.
If the child or parent node is selected I want open the parent node.
Given that if the parent node is selected all the children are selected as well.
 
Thanks in Advance, got my 5 star anyways
GeneralHi Ralph VarjabedianmemberMagesh Murugesan10 Jan '10 - 23:35 
Nice article. But we have use MVP architecture, So we are not use dataset and table in view layer(use only list collection). This case how can load treeview controls with multilevel trrnodes.
GeneralUtterly awesome!memberdropit2 Oct '08 - 3:22 
Thanks, this saved my day!!! Cool | :cool:
GeneralRe: Utterly awesome!memberRalph Varjabedian2 Oct '08 - 22:35 
You're welcome.
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralSlight bug in thismemberDMardell2 Sep '08 - 2:35 
Excellent code sample. Exactly what I was after!
 
However theres a small bug in the sample provided which throws with both the dataset you provide, and my own SQL datasource.
 
"public IEnumerator GetEnumerator()" throws StackOverflowException after getting stuck in an infinite loop as a result of "public bool HasChildren" always returning true.
 
Haven't quite got to the bottom of it yet but it seems to be stemming from the various cleardowns of the RowFilter you use for recursion. By Setting RowFilter="" its getting "stuck".
GeneralRe: Slight bug in thismemberRalph Varjabedian2 Sep '08 - 3:26 
I will check my dataset again because as I recall, my test case was working correctly...
As for your data, maybe the reason is that the parent IDs are not null but are set to zero to indicate (no parent). If you can please do pass me a sample of your data (if you want, just load them into a DataSet and call ExportXML) and send them to me and I will make sure I test your data and fix any possible bugs.
 
Thanks again.
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Slight bug in thismemberDMardell2 Sep '08 - 8:23 
My ParentID are also null. Was getting the same problem with the hardcoded DataSet in the example above as well.
GeneralRe: Slight bug in thismemberRalph Varjabedian2 Sep '08 - 22:37 
That is strange, I had someone report to me the same problem, however I do have it running normally on my machine. Since I can not reproduce the problem, I guess I can guide you to do some debugging. Put a breakpoint on lines that have the RowFilter. And try to see what is happening there.
Thanks,
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Slight bug in thismemberDMardell5 Sep '08 - 10:36 
Hi Ralph. I did spend quite a bit of time debugging this before I posted - figued I could fix it on my own but I was wrong Smile | :)
 
Found that by eliminating the 'RowFilter=""' statements that I escaped the infinite loop - which was nice!
 
However this threw up more porblems (expectedly) with errors of "No row at position 0" when reaching the last child in the datasource (be it my database or your hard coded sample)
 
I suspect it may be something with my set up. If I download the code sample provided and try and open the project file VS returns an error "not supported by this instalation". I had to create a new project and start adding the files in manually to get it going - which might be why it works for you and not me!
 
As it stands I gave up and found an alternative solution. I now load the dataset from the DB and using a recursive call to a method that uses the same principle as your "public IEnumerator GetEnumerator()" I generate a string of "Hierachical" XML
 
From there its just a case of setting an "XMLDataSource.Data = xmlString" and then binding the treeView to that XMLDataSource.
 
Not nesisarily a BETTER soloution - but I got it going. And I would never have had the inspiration if not for this article. So for that - I thank you. Saved me a big headache!
GeneralVery nicememberMR_SAM_PIPER7 May '08 - 14:14 
Simple, elegant, non-smelly. A pity that other developers can't see the point of this example...
GeneralRe: Very nicememberRalph Varjabedian7 May '08 - 21:19 
Thank you. A lot of developers have shared your point of view so far.
When I have time next, I am going to update the article and the code to support LINQ as well.
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralNot so nice though!memberBalamurali Balaji2 May '08 - 22:51 
Treeview control supports XmlDataSource; a dataset may be stored as a xml file and can be bound to the treeview control.
 
You don't even write this much of code to build a dataset programmatically and then do the binding.
 
The article is not even good for novice developers.
 
balamurali balaji
MVP (ASP.NET, Visual C# & Device Application Development)
homepage: http://h1.ripway.com/bbmurali_2000

GeneralRe: Not so nice though!memberRalph Varjabedian3 May '08 - 2:33 
Thank you for sharing,
 
Even though the TreeView control supports XmlDataSource and even if you save the file as xml and read it into an XmlDataSource, how are you going to bind the linear structure to a parent-child relationship! Confused | :confused: Please if you have some code or a url that shows this in action, let us know. Thank you. The binding problem is not just type based (can not bind to a DataSet) it is also logical based (can not bind to a linear structure). My class takes two column names and generates this parent-child structure for you.
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Not so nice though!memberBalamurali Balaji3 May '08 - 4:24 
Once data is made available in Xml form, whether it is in linear form or hierarchical or in a form that represents parent-child relationship, you may configure the treenode bindings property to reflect the same.
 
Pls. refer the msdn page that shows an example of using treeview and explains xmldatasource also.
 
http://msdn.microsoft.com/en-us/library/system.web.ui.webcontrols.xmldatasource.aspx.
 
balamurali balaji
MVP (ASP.NET, Visual C# & Device Application Development)
homepage: http://h1.ripway.com/bbmurali_2000

GeneralRe: Not so nice though!memberRalph Varjabedian3 May '08 - 6:59 
I am looking at the page you sent me, it is a definition of the XmlDataSource class.
I still can not see how the data that you saved in XML which does not have child nodes (as xml), is going to be presented in the tree view based on two columns, (parent-child) relationship. Look at the data binding section that you sent me in the ASP.NET TreeView, how do you do that :confusd: there is only one way to bind to the XmlDataSource that it is simply: datamember and textfield. Have you done this before? have you seen the code somewhere, or are you just assuming that since a DataSet can be saved as an xml file and you can read it through XmlDataSource that it will automatically be done. I still can not see your solution. You are missing the main point that a DataSet when saved as XmlFile has a linear structure, it will not be saved as parent and child nodes!
 
Thank you.
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Not so nice though!memberBalamurali Balaji3 May '08 - 8:11 
Here is one article that shows how to bind dataset to a treeview.
 
http://dn.codegear.com/article/27879
 
Though this article does not shows how to use xml data, it shows how rows are loaded from the child dynamically, in the onexpanding event handler. Similarly, we could parse the xml-file created by the dataset, first with master table and then with child table on user-intervention which is more efficient. This is the logic I was thinking of when it comes to dataset-treeview binding. In your article, you have just shown how to use the series of IHierarchy interfaces to define a dataset suitable for tree-view binding.
 
And it shows a dataset which is static. Does it work for dynamic data retrieved from a database?
 
Right now, I dont have time work upon it and send you the copy of the results.
 
balamurali balaji
MVP (ASP.NET, Visual C# & Device Application Development)
homepage: http://h1.ripway.com/bbmurali_2000

GeneralRe: Not so nice though!memberRalph Varjabedian3 May '08 - 11:12 
Yes I am familiar with this method...
 
The method presented in my article is much easier, I would rather write one line of code than to do what the article you mentioned is doing Smile | :) handle events and for each TreeView control you add, there is just too much housekeeping compared with what I presented. As I said in the beginning there is no easy direct way to do this without doing extra coding. And even with your suggestion of XmlDataSource, you can not do that, putting the data in xml format is not enough to have the parent-child relationship. All you will have is linear data.
 
With my method, all you do is this:
TreeView1.DataSource = new HierarchicalDataSet(dataSet, "ID", "ParentID");
 
Now unless there is something I am not seeing, I have introduced the easiet way to do this so far.
 
And I did not understand what you meant by static dataset Smile | :) You can bind my class with any dataset you want, dynamic or static, from database or from xml or from manually added rows or from loaded from file or deserialized! There is really no difference all you have to do it point my class to two column names.
 
When I have time next, I am going to do that with LINQ, so you will be able to bind the results of LINQ to a TreeView also with one line of code.
 
Thank you for sharing your ideas and urls.
Have a nice day.
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Not so nice though!memberBalamurali Balaji3 May '08 - 18:00 
Hi Ralph,
 
I accept the statement,
 
TreeView1.DataSource = new HierarchicalDataSet(dataSet, "ID", "ParentID");
is quicker and easier.
 
But, remember where the dataset comes from. you need to build yourself a dataset implementing IHierarchy.. interfaces and populate the dataset in the code. This dataset I call it as static dataset( static data).
 
But in real-world applications, most of the times, dataset is created out of an existing datasource. Does your method works with dynamic data coming from a datasource? Do you have any ideas on combining such a dataset and IHierarchy?
 
Anyway, thank you very much for your co-operation in clarifying the article so far.
 
balamurali balaji
MVP (ASP.NET, Visual C# & Device Application Development)
homepage: http://h1.ripway.com/bbmurali_2000

GeneralRe: Not so nice though!memberRalph Varjabedian4 May '08 - 1:03 
You're welcome for the clarification. My end target is for as much developers as possible to benefit from this.
 
I am not building a dataset myself that is implementing IHierarchy.... Please take a closed look at the code. The class that I am creating implements the Interface and keeps a reference to the passed in dataset. Anytime methods of the Interface are called, they are properly translated and the correct DataRowViews are returned that "describe" the parent-child data that should be returned. These decisions made by my class are based on the two column names that you pass in.
 
So to answer your question, yes my method works with any dynamic data coming from any data source. It does not matter as long as this data has two columns that create the circular reference that I talked about in my article that will help my class "see" the parent-child relationships.
 
Hope this helps.
Have a nice day.
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Not so nice though!memberBalamurali Balaji4 May '08 - 3:41 
Yeah.. it is supposed to work the way you have mentioned.
 
I have explored your sample thoroughly and I could see only one table data in your dataset. If its a master-detail(parent-child) relationship stored in the dataset, it is supposed to have two tables in the dataset.
 
This means that you represent data in one table in hierarchical fashion. Within a table, you have assumed two columns as parent and child columns. But, not, displaying data from two tables related to each other by common column. If this is the case, where comes the parent-child relationship?
 
My understanding is that you are displaying data from parent and child table. I am still worried about this aspect.
 
balamurali balaji
MVP (ASP.NET, Visual C# & Device Application Development)
homepage: http://h1.ripway.com/bbmurali_2000

GeneralRe: Not so nice though!memberRalph Varjabedian4 May '08 - 5:05 
Yes, you only have one table and not two tables. You do not need two tables to have master-detail relationship you only need one. And often in these cases it is one since you are displaying the same type of data (same table with circular reference) and not two tables because they have exactly the same columns, I am surprized you are not familier with this database "modeling method". And if you do have two, then a simple inner join can make them into one, covering both cases.
 
The parent-child relationship comes from the circular reference (foriegn key to the table itself), please see the table example model. This is a typical method of creating parent-child relationship and model it in databases, it is a well known method.
 
Well as I said, if you just have one table, with circular reference then your data is done, if you have two tables and inner join will easily make the data into one dataset. Read the first comment on my blog on this topic, someone is explaning a live database table that they used my method for.
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



GeneralRe: Not so nice though!membernutwiss14 May '08 - 5:23 
Agreed. It is entirely common practice to present arbitrarily deep hierarchies as single, self-referencial tables.
 
This is problem being overcome by this solution.
 
Baramurali's master-child relationship, as he correctly points out would be stored in two seperate tables and could, as he points out, be represented and passed to a treeview via XML.
 
However, this is not the problem presented, nor that solved. The problem presented is that of self-referencial, hierarchical data, presented in a flat table structure, not that of *intrinsically* hierarchical XML data, which, let's be honest, is a doddle to data-bind.
 
This is good solution to a tricky problem.
GeneralRe: Not so nice though!memberrexahs7 Oct '08 - 6:38 
I have to agree with nutwiss. This is an entirely normal situation and this is a good solution to the problem. I think a slight extension (overload) would be to refactor to allow a DataTable to be passed and not to select just table[0] but this is a matter of minute detail in the scheme of things. Great share which is much appreciated Big Grin | :-D . Why MS did not do this within the framework is a puzzle, but they probably have other things to do...
GeneralRe: Not so nice though!memberRalph Varjabedian9 Oct '08 - 23:08 
Hi, Thank you for your comment. I am preparing an update to the code soon, there are several points that the readers have noted that will be included in this update. You can check my blog on more readers' comments on this.
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



QuestionWhy didn't Microsoft provide this? Can you make this work with custom collection?memberdefwebserver2 May '08 - 10:04 
If I could build a custom collection in Linq and pass that in it would be great. Anyway you got my 5.
AnswerRe: Why didn't Microsoft provide this? Can you make this work with custom collection?memberRalph Varjabedian2 May '08 - 13:27 
Interesting, I am going to look into your suggestion and I should be able to do it if it can be done.
Stay tuned Smile | :)
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



AnswerRe: Why didn't Microsoft provide this? Can you make this work with custom collection?memberRalph Varjabedian8 May '08 - 23:11 
You can transform your custom collection to a DataView via AsDataView() method.
And as such, you will be able to bind it easily with my code.
 
I am posting an update soon which will enable the class to bind with a dataview rather than a dataset.
 
Hope this helps.
 
Ralph Varjabedian
Chief Software specialist

My Blog
Bytesurge.com



General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130516.1 | Last Updated 2 May 2008
Article Copyright 2008 by Ralph Varjabedian
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid