Binding a TreeView to a DataSet

This blog entry demonstrates the fundamentals of binding a WPF TreeView to a DataSet with two related DataTables. The technique presented herein could easily be extended to fit more sophisticated requirements, such as binding to more than two tables.

Many applications need to display hierarchical data in a TreeView, and often that data is retrieved from a database. In many situations the developer just needs to bind the TreeView directly to the DataSet which was populated with database data; creating custom domain objects and collections of those objects can be overkill sometimes. If you are currently in that situation, rest assured that it is actually fairly trivial to do this in WPF. 🙂

The basic gist of the solution is to bind the top level of TreeViewItems against the master DataTable, and then bind against DataRelations for any descendants of the root nodes. You need to use a HierarchicalDataTemplate for every non-leaf level of nodes, in other words, only the very lowest DataTable in the hierarchy is displayed with a non-hierarchical DataTemplate.

Let’s just get right into an example. Here is a method in a class called DataSetCreator which creates a DataSet with two related DataTables:

Creating a hierarchical DataSet

The resultant DataSet has two DataTables (‘Master’ and ‘Detail’) and one DataRelation (‘Master2Detail’). We want a TreeView to display the Master rows as top-level nodes and the Detail rows as children of their respective parent node. Here is the XAML for a Window which contains a TreeView configured to load and display that data:

Binding a TreeView to a DataSet

If you had, say, three related tables (Master –> Detail –> DetailInfo) then you could have the ‘DetailTemplate’ be a HierarchicalDataTemplate whose ItemsSource was bound to the DataRelation between ‘Detail’ and ‘DetailInfo,’ and the ItemTemplate a DataTemplate which displays the pertinent information in that table.

When you run the demo application and expand the root nodes, the TreeView looks like this:

The bound TreeView

 Click here to download the demo project.  Be sure to change the file extension from DOC to ZIP and then unzip it.

39 Responses to Binding a TreeView to a DataSet

  1. It is really easier than with “classic” WinForms !

  2. Josh Smith says:

    Matthieu,

    It certainly is. The WinForms TreeView does not provide any way to automatically generate its nodes based on a data source. The WPF TreeView makes this very easy. WPF rocks!

    Josh

  3. […] Josh Smith on WPF – Hierarchal Data Binding […]

  4. Michael says:

    I am a complete noob at this so bear with me.

    When I open the Window1.xaml, I get an error:

    Assembly ” was not found. The ‘clr-namespace’ URI refers to an assembly that is not referenced by the project.

    Am I missing something?

  5. Michael says:

    I had a look through the WPF Forums and consensus was that this is a bug.

  6. Josh Smith says:

    Michael,

    Visual Studio’s XAML support is not quite “there yet.” It gives warnings for perfectly valid XAML constructs, which you can safely ignore.

    Josh

  7. Govind says:

    Is there any way to select a treeview node (arbitrary child object) by passing a key, like we used to do in Windows common control library. ?
    When we want to select a Node, we could write this in VB6:

    Set tvw.SelectedItem = tvw.Nodes.Items(“KEY1”)

    “KEY1” is a unique key for every node, Unique key was assigned while populating the treeview.

    Additionally how to use tvw.Items.Contains method ?
    I think contains method only work at own level (not nested). Because Items collection is a new object for each child treeviewitem, this is very bad and consuming lots of memory, anyways, please help me.
    Thanks.
    Govind

  8. Josh Smith says:

    Govind,

    No, TreeViewItems in WPF do not have a Key property.

    The Items collection of TreeView only contains the data objects represented by the root-level nodes. You must use a recursive technique to walk through the items and set the IsSelected property to true on the TreeViewItem which you want to select.

    Josh

  9. Govind says:

    Thanks Josh, But IsSelected is a read-only property, I remebered
    I tried the recursive technique for checking the desired object existance, But I think ICompare interface can help me for nodes comparsion this will also help me in sorting the tree, I will try this.

    Additionally, I saw a method in Items property called MoveToCurrent (not exactly sure the name) as per doc it will select given node or will return false upon failure. But this method is also doesn’t work for me and always returns fails even I passed a true object. I will submit my code tomorrow. Many many thanks for replying.
    Govind

  10. Josh Smith says:

    Govind,

    You should post further questions/code on the WPF Forum: http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=119&SiteID=1

    Josh

  11. George says:

    Hi,
    What about the case where you have a single table with a self reference?
    I’ve tried to modify the code but no luck 😦

  12. Josh Smith says:

    George,

    Hmmm, that’s an interesting question. You might want to search the WPF Forum, or post a question about it if you can’t find an answer. I’ve never tried to do that in WPF before.

    Josh

  13. LE Marek says:

    I used this binding(solution1), works good, but some thing works else then if I fill TreeView by treeview.Items.Add() (solution2).

    For example:
    1) change Foreground of selected node. I get from treeview.SelectedItem
    Sol 2: TreeViewItem
    Sol 1: DataRowView
    > So how can I access to treeviewitem.Foreground, if I get DataRowItem, respectively, how to change color of text of selected node?

    2) using treeview.FindName(registeredName)
    >What is registered name in sol 1? So how can I find node if I know ID of row from table to be able for example change text color?

    Any help welcome.
    Thanks,

    Marek

  14. Abhinav says:

    Hi,
    i have bound the TreeView to the Dataset and geet the Item. But they not TreeView Item . Neither I can TypeCast them to Treeview. Actually i want to write a Event Handleron the click of the Items. How can I do this?

    Bye

  15. Josh Smith says:

    For general purpose questions about WPF, you should ask them on the WPF Forum: http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=119&SiteID=1 First search the forum to see if the question has already been answered.

    If you have a question which relates to the topic of a blog post, then leave it as a comment on that post.

    Thanks,
    Josh

  16. Abhinav says:

    Hi,

    Can we do this when there are more than a DataRelation and I Want multiple levels i.e Nested Nodes.

    Thanks
    Abhinav

  17. Radek says:

    Hi.

    Help me please. A need more as two tables bind to a treeview. Between tables in dataset I have relations. But this work onlly between two tables.

    Can we write any examle me.

    I have Visual C# 2008 Express.

    Radek

  18. Josh Smith says:

    Abihav,
    This post mentions that situation, under the xaml snippet.

    Radek,
    I’m not going to write an example for you. If you have a question which needs to be answered with any urgency, don’t post it here. Post it to the WPF Forum: http://forums.microsoft.com/MSDN/ShowForum.aspx?ForumID=119&SiteID=1

    Josh

  19. Eric Cosky says:

    Very informative example. Thanks for the write up!

  20. Hi,

    The code works fine to fill a treeview with a dataset.
    But, since you don’t use a treeview.item, how can you directly expand the whole treeview?

    Freddy.

  21. Geert Diddens says:

    Hi Freddy,

    You should use a style for this (put it in the Xaml file, before the treeview :

    greetz
    Geert D.

  22. Geert Diddens says:

    Hi Freddy,
    Put this in your XAML file (before the treeview). ( Change the ‘{‘ to ”, had do this, because the code wouldn’t post otherwise)

    {ResourceDictionary}
    {Style TargetType=”TreeViewItem”}
    {Setter Property=”IsExpanded” Value=”True”/}
    {/Style}
    {/ResourceDictionary}
    greetz
    Geert

  23. Kieran says:

    Great TreeView, but is there any way to implement sorting of the tree nodes??
    I have tried sorting the data withjin the dataset but I can’t get the tree view to update – any ideas??

  24. Josh Smith says:

    Kieran,

    When you bind to a collection, you’re actually binding to an ICollectionView implementation wrapped around the collection. ICollectionView supports sorting.

    Josh

  25. Plastio says:

    What about one table which is arranged with parentID and ObjectID kind a like internal hirarchy ?
    any ideas how not to break balls around this issue please ?

    ADV thanks ANCE

  26. Azat says:

    Hi Josh!

    You showed an example with Dataset. What about LINQ to SQL classes? I couldn’t find anything bout that. Can you help me, please? Thanx… 😉

  27. Deepak says:

    Hi,
    I am not able to open the unzipped solution file so I copied code to my test application and when I tried to run my test application I got following error.

    “Failed object initialization (ISupportInitialize.EndInit). Exception has been thrown by the target of an invocation. Error at object ‘dataSetProvider’ in markup file ‘ResearchOnWPF;component/window1.xaml’ Line 12 Position 7.

    It seems like some problem is there with “” this line.

  28. Vipul says:

    Hi,

    I have a DB table [1] which is self referenced. DataID field is the FK of ParentDataID field. For multilevel hierarchical data binding to a WPF tree view control, I have a stored procedure that returns result set in the below mentioned order[1]. The below result set contains all the top level data with NULL ParentDataID data & all the child records has the ParentDataID field data as the pointer to its parent data.

    Based on the below dataset structure, we have a requirement to bind the resultset with the multi level hierarical data to the TreeView control. How can we achive this funcionality of binding the dynamic hierarical multi level dataset to TreeView?

    After binding the above result set, the Tree View data needs to be displayed in the below format. How do we implement this in the WPF Tree View?

    * Test 1
    * Test 2
    * Test 5
    * Test 3
    * Test 6
    * Test 4

    [1]

    DataID ParentDataID Description

    1 NULL Test 1
    2 1 Test 2
    3 1 Test 3
    4 1 Test 4
    5 2 Test 5
    6 3 Test 6

    Regards,
    Vipul Mehta

  29. Behrang says:

    Hi Josh

    I,m a project manager and we are going to use WPF technology in the project and I have alot problem with WPF Treeview 😦

    How can I fill a TreeView with a List of a Data object that it has a List of other Data Object with N level and the Data object will be filled in run time?
    I want to get the tree view automatically suitable Levels for each nested Data Object without using of HirarchcalDataTemplate. As u know we can do it in the Windows Treeview with defining a parent object and related DiplayValue!!! Please help me with a sample.

    My Data Objects are for example :

    public class CustomerDTO
    {
    public string Name{get;set;}
    .
    .
    .

    public IList {get;set;}
    }

    public class OrderDTO
    {
    public string OrderDate{get;set;}
    .
    .
    .

    public IList {get;set;}
    }

    public class OrderDetailDTO
    {
    public string Quantity{get;set;}
    .
    .
    .

    }

  30. Joel says:

    How about using Linq to SQL to retreive a result and then using that result to fill a HierarchicalDataTemplate in a TreeView, Doesn’t seem to work for me. Any Idea’s anyone?

    Regards
    Joel

  31. Creddath says:

    thanks much, dude

  32. Thiruppathy says:

    Nice Sample, simple & informative. Thank you Smith!

  33. Abdul says:

    hello.
    i have tow database.int hat two database they have four table.lke parent and child tables.i want bind the two database table at the same time in treeview format.how i can bind the two database tables in treeview format using c#.plz help i need full codeing

  34. eddie says:

    How do I make the TreeView/DataSet automatically refresh when a child record changes in the database?

  35. xmap says:

    Since everybody points to this blog entry when talking about binding treeview to a dataset (i haven’t found a solution for it anywhere else), please provide some additional info on the following:
    1. When you bind to the DataRelation, and the child rows change, your treeview will not update. this is probably due to DataSet delegating change notificatios to some wrapper (i’m not sure which). how do you refresh that?
    2. With more than 2 levels of hierarchy you cannot use HierarchicalDataTemplate as a DynamicResource for ItemTemplate. Is there another way of having multiple HierarchicalDataTemplates referring to each other?