New to Telerik UI for WPF? Download free 30-day trial

Building Hierarchical Grid

This tutorial will walk you through the process of displaying hierarchical data in RadGridView. It will not cover the creation of a WPF application, adding RadGridView to your UserControl or how to define columns. If you need information on any of these topics please read the Getting Started topic.

The final result should look like the one displayed on Figure 1.

Figure 1: Hierarchical RadGridView

Telerik WPF DataGrid Building Hierarchical Grid

Assuming that you have already created a WPF application and defined the RadGridView control, it is time to prepare the sample data for it.

Preparing the Data

The sample data is represented by teams divided into divisions. First create the class that will represent a single team.

Example 1: The Team class

public class Team 
{ 
    public int Id 
    { 
        get; 
        set; 
    } 
    public string Name 
    { 
        get; 
        set; 
    } 
    public int Place 
    { 
        get; 
        set; 
    } 
} 
Public Class Team 
    Private _Id As Integer 
    Public Property Id() As Integer 
        Get 
            Return _Id 
        End Get 
        Set(ByVal value As Integer) 
            _Id = value 
        End Set 
    End Property 
 
    Private _Name As String 
    Public Property Name() As String 
        Get 
            Return _Name 
        End Get 
        Set(ByVal value As String) 
            _Name = value 
        End Set 
    End Property 
 
    Private _Place As Integer 
    Public Property Place() As Integer 
        Get 
            Return _Place 
        End Get 
        Set(ByVal value As Integer) 
            _Place = value 
        End Set 
    End Property 
End Class 

The class that represents a single division will contain a collection of Team objects.

Example 2: The Division class

public class Division 
{ 
    public int Id 
    { 
        get; 
        set; 
    } 
    public string Name 
    { 
        get; 
        set; 
    } 
    public List<Team> Teams 
    { 
        get; 
        set; 
    } 
} 
Public Class Division 
    Private _Id As Integer 
    Public Property Id() As Integer 
        Get 
            Return _Id 
        End Get 
        Set(ByVal value As Integer) 
            _Id = value 
        End Set 
    End Property 
 
    Private _Name As String 
    Public Property Name() As String 
        Get 
            Return _Name 
        End Get 
        Set(ByVal value As String) 
            _Name = value 
        End Set 
    End Property 
 
    Private _Teams As List(Of Team) 
    Public Property Teams() As List(Of Team) 
        Get 
            Return _Teams 
        End Get 
        Set(ByVal value As List(Of Team)) 
            _Teams = value 
        End Set 
    End Property 
End Class 

Note that if you want to support two way binding your classes should implement the INotifyPropertyChanged interface and raise the PropertyChanged event every time a property value changes.

Create a DivisionsService class and implement a static method GetDivisions. For the purpose of this tutorial it will return an observable collection containing several hard-coded divisions.

Example 3: The DivisionsService class

public class DivisionsService 
{ 
    public static ObservableCollection<Division> GetDivisions() 
    { 
        ObservableCollection<Division> divisions = new ObservableCollection<Division>(); 
        Division dA = new Division(); 
        dA.Name = "Division A"; 
        dA.Id = 1; 
        dA.Teams = new List<Team>(); 
        Team team1 = new Team(); 
        team1.Id = 1; 
        team1.Name = "Team I"; 
        team1.Place = 1; 
        dA.Teams.Add(team1); 
        Team team2 = new Team(); 
        team2.Id = 2; 
        team2.Name = "Team II"; 
        team2.Place = 2; 
        dA.Teams.Add(team2); 
        Team team3 = new Team(); 
        team3.Id = 3; 
        team3.Name = "Team III"; 
        team3.Place = 3; 
        dA.Teams.Add(team3); 
        divisions.Add(dA); 
        Division dB = new Division(); 
        dB.Name = "Division B"; 
        dB.Id = 2; 
        dB.Teams = new List<Team>(); 
        Team teamRed = new Team(); 
        teamRed.Id = 1; 
        teamRed.Name = "Team Red"; 
        teamRed.Place = 1; 
        dB.Teams.Add(teamRed); 
        Team teamGreen = new Team(); 
        teamGreen.Id = 2; 
        teamGreen.Name = "Team Green"; 
        teamGreen.Place = 2; 
        dB.Teams.Add(teamGreen); 
        Team teamBlue = new Team(); 
        teamBlue.Id = 3; 
        teamBlue.Name = "Team Blue"; 
        teamBlue.Place = 3; 
        dB.Teams.Add(teamBlue); 
        divisions.Add(dB); 
 
        Division dC = new Division(); 
        dC.Name = "Division C"; 
        dC.Id = 3; 
        dC.Teams = new List<Team>(); 
        Team teamAlpha = new Team(); 
        teamAlpha.Id = 1; 
        teamAlpha.Name = "Team Alpha"; 
        teamAlpha.Place = 1; 
        dC.Teams.Add(teamAlpha); 
        Team teamBeta = new Team(); 
        teamBeta.Id = 2; 
        teamBeta.Name = "Team Beta"; 
        teamBeta.Place = 2; 
        dC.Teams.Add(teamBeta); 
        Team teamGama = new Team(); 
        teamGama.Id = 3; 
        teamGama.Name = "Team Gama"; 
        teamGama.Place = 3; 
        dC.Teams.Add(teamGama); 
        divisions.Add(dC); 
        return divisions; 
    } 
} 
Public Class DivisionsService 
    Public Shared Function GetDivisions() As ObservableCollection(Of Division) 
        Dim divisions As New ObservableCollection(Of Division)() 
 
        Dim dA As New Division() 
        dA.Name = "Division A" 
        dA.Id = 1 
        dA.Teams = New List(Of Team)() 
        Dim team1 As New Team() 
        team1.Id = 1 
        team1.Name = "Team I" 
        team1.Place = 1 
        dA.Teams.Add(team1) 
        Dim team2 As New Team() 
        team2.Id = 2 
        team2.Name = "Team II" 
        team2.Place = 2 
        dA.Teams.Add(team2) 
        Dim team3 As New Team() 
        team3.Id = 3 
        team3.Name = "Team III" 
        team3.Place = 3 
        dA.Teams.Add(team3) 
        divisions.Add(dA) 
 
        Dim dB As New Division() 
        dB.Name = "Division B" 
        dB.Id = 2 
        dB.Teams = New List(Of Team)() 
        Dim teamRed As New Team() 
        teamRed.Id = 1 
        teamRed.Name = "Team Red" 
        teamRed.Place = 1 
        dB.Teams.Add(teamRed) 
        Dim teamGreen As New Team() 
        teamGreen.Id = 2 
        teamGreen.Name = "Team Green" 
        teamGreen.Place = 2 
        dB.Teams.Add(teamGreen) 
        Dim teamBlue As New Team() 
        teamBlue.Id = 3 
        teamBlue.Name = "Team Blue" 
        teamBlue.Place = 3 
        dB.Teams.Add(teamBlue) 
        divisions.Add(dB) 
 
        Dim dC As New Division() 
        dC.Name = "Division C" 
        dC.Id = 3 
        dC.Teams = New List(Of Team)() 
        Dim teamAlpha As New Team() 
        teamAlpha.Id = 1 
        teamAlpha.Name = "Team Alpha" 
        teamAlpha.Place = 1 
        dC.Teams.Add(teamAlpha) 
        Dim teamBeta As New Team() 
        teamBeta.Id = 2 
        teamBeta.Name = "Team Beta" 
        teamBeta.Place = 2 
        dC.Teams.Add(teamBeta) 
        Dim teamGama As New Team() 
        teamGama.Id = 3 
        teamGama.Name = "Team Gama" 
        teamGama.Place = 3 
        dC.Teams.Add(teamGama) 
        divisions.Add(dC) 
 
        Return divisions 
    End Function 
End Class 

Now after the sample data is prepared you are ready to bind it to the RadGridView. To do this set the ItemsSource property of the grid to the collection returned by the GetDivisions method. But first define the following columns.

Example 4: Defining the RadGridView

<telerik:RadGridView x:Name="HierarchicalGridView" 
                 AutoGenerateColumns="False"> 
    <telerik:RadGridView.Columns> 
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Id}" 
                                Header="Id" /> 
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}" 
                                Header="Name" /> 
    </telerik:RadGridView.Columns> 
</telerik:RadGridView> 

Set the ItemsSource in the code-behind file of your UserControl.

Example 5: Setting the control's ItemsSource

this.HierarchicalGridView.ItemsSource = DivisionsService.GetDivisions(); 
Me.HierarchicalGridView.ItemsSource = DivisionsService.GetDivisions() 

If you run the application at this stage you will observe the result from Figure 2.

Figure 2: RadGridView without a hierarchy

Telerik WPF DataGrid No Hierarchy

Defining ChildTableDefinitions

The next step is to make the RadGridView display the collections of teams as children of the respective rows. To do that use the ChildTableDefinitions property of the RadGridView and define a new GridViewTableDefinition with the following relation.

Example 6: Defining ChildTableDefinitions

<telerik:RadGridView x:Name="HierarchicalGridView" AutoGenerateColumns="False"> 
    <telerik:RadGridView.ChildTableDefinitions> 
 
        <telerik:GridViewTableDefinition> 
            <telerik:GridViewTableDefinition.Relation> 
                <telerik:PropertyRelation ParentPropertyName="Teams" /> 
            </telerik:GridViewTableDefinition.Relation> 
        </telerik:GridViewTableDefinition> 
 
    </telerik:RadGridView.ChildTableDefinitions> 
    <telerik:RadGridView.Columns> 
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Id}" 
                                Header="Id" /> 
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}" 
                                Header="Name" /> 
    </telerik:RadGridView.Columns> 
</telerik:RadGridView> 

You can read more about the GridViewTableDefinition here.

After defining the definitions you will observe the hierarchical grids as illustrated on Figure 3.

Figure 3: RadGridView with a hierarchy

Telerik WPF DataGrid with a Hierarchy

HierarchyChildTemplate

If you need to set properties of the child RadGridView instances, you can use the HierarchyChildTemplate.

Example 7: Setting the control's HierarchyChildTemplate

<telerik:RadGridView x:Name="HierarchicalGridView" AutoGenerateColumns="False" GroupRenderMode="Flat"> 
    <telerik:RadGridView.ChildTableDefinitions> 
        <telerik:GridViewTableDefinition> 
            <telerik:GridViewTableDefinition.Relation> 
                <telerik:PropertyRelation ParentPropertyName="Teams" /> 
            </telerik:GridViewTableDefinition.Relation> 
        </telerik:GridViewTableDefinition> 
    </telerik:RadGridView.ChildTableDefinitions> 
    <telerik:RadGridView.Columns> 
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Id}"  
                        Header="Id" /> 
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"  
                        Header="Name" /> 
    </telerik:RadGridView.Columns> 
    <telerik:RadGridView.HierarchyChildTemplate> 
        <DataTemplate> 
            <telerik:RadGridView ShowGroupPanel="False" AutoGenerateColumns="False" ItemsSource="{Binding Teams}" GroupRenderMode="Flat"> 
                <telerik:RadGridView.Columns> 
                    <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"  
                        Header="Name" /> 
                    <telerik:GridViewDataColumn DataMemberBinding="{Binding Place}"  
                        Header="Place" /> 
                </telerik:RadGridView.Columns> 
            </telerik:RadGridView> 
        </DataTemplate> 
    </telerik:RadGridView.HierarchyChildTemplate> 
</telerik:RadGridView> 

The final result is observed on Figure 4.

Figure 4: Customized child grids

Telerik WPF DataGrid with Customized Child Grids

You can also use the HierarchyChildTemplateSelector property to specify a DataTemplateSelector and provide different templates for the child elements based on the parent row which is expanded.

To learn more about the Hierarchical Grids you can visit the Hierarchical GridView section.

See Also

In this article