Edit this page

Getting Started

This article will guide you through the process of creating a sample application with RadTreeListView.

RadTreeListView vs RadGridView

You should use the RadTreeListView control to display hierarchical data in a tabular format. In order to achieve this, the control combines the functionality of RadGridView control with the ability to display data in a tree view manner. This is implemented by directly inheriting RadGridView and implementing the tree view behavior.

RadTreeListView displays the data in the same way as RadGridView. The difference is that each row plays the role of a tree node, which can be expanded or collapsed.

Please note that RadTreeListView and the Hierarchical RadGridView are two different things. The first displays the data in a tree view manner in one and the same table. The second one displays the hierarchical data in nested RadGridViews.

Use RadTreeListView only when you need to display homogeneous data. For heterogeneous data use the Hierarchical RadGridView.

You can also check out the RadGridView's Getting Started section.

Assembly References

In order to use the RadTreeListView in your application, you should add references to the following assemblies:

  • Telerik.Windows.Controls

  • Telerik.Windows.Controls.GridView

  • Telerik.Windows.Data

  • Telerik.Windows.Controls.Input

Add RadTreeListView to the Project

After you make sure you have added the needed assembly references, you can either add the control manually by writing the XAML code (Example 2) or you can drag it from the Visual Studio Toolbox and drop it over the XAML view.

In order to use RadTreeListView in XAML, you have to declare the following namespace:

Example 1: Declaring Telerik Namespace

Example 2: Adding RadTreeListView in XAML

<telerik:RadTreeListView x:Name="radTreeListView">
</telerik:RadTreeListView>

Populating with Data

Populating RadTreeListView with sample data will require a business model and a view model that exposes a collection that the control can be bound to. This section will cover the process of defining them.

The example will use a collection that represents the contents of a warehouse. It will contain WarehouseItem objects. Each WarehouseItem will have a Name, Count and a collection of WarehouseItem objects. Here is the class definition.

Example 3: Defining a Sample Business Model

public class WarehouseItem: INotifyPropertyChanged
{
    private string name;
    private int count;
    private ObservableCollection<WarehouseItem> items;

    public WarehouseItem(string name, int count)
    {
        this.Name = name;
        this.Count = count;
        this.Items = new ObservableCollection<WarehouseItem>();
    }
    public string Name
    {
        get 
        {
            return this.name;
        }
        set 
        {
            if (value != this.name)
            {
                this.name = value;
                this.OnPropertyChanged("Name");
            }
        }
    }
    public ObservableCollection<WarehouseItem> Items
    {
        get 
        {
            return this.items;
        }
        set 
        {
            if (value != this.items)
            {
                this.items = value;
                this.OnPropertyChanged("Items");
            }
        }
    }
    public int Count
    {
        get 
        {
            return this.count;
        }
        set 
        {
            if (value != this.count)
            {
                this.count = value;
                this.OnPropertyChanged("Count");
            }
        }
    }

    protected virtual void OnPropertyChanged(PropertyChangedEventArgs args)
    {
        PropertyChangedEventHandler handler = this.PropertyChanged;
        if (handler != null)
        {
            handler(this, args);
        }
    }

    private void OnPropertyChanged(string propertyName)
    {
        this.OnPropertyChanged(new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
}
    Public Class WarehouseItem
    Implements INotifyPropertyChanged

    Private _name As String
    Private _count As Integer
    Private _items As ObservableCollection(Of WarehouseItem)

    Public Sub New(ByVal name As String, ByVal count As Integer)
        Me.Name = name
        Me.Count = count
        Me.Items = New ObservableCollection(Of WarehouseItem)()
    End Sub
    Public Property Name() As String
        Get
            Return Me._name
        End Get
        Set(ByVal value As String)
            If value <> Me._name Then
                Me._name = value
                Me.OnPropertyChanged("Name")
            End If
        End Set
    End Property
    Public Property Items() As ObservableCollection(Of WarehouseItem)
        Get
            Return Me._items
        End Get
        Set(ByVal value As ObservableCollection(Of WarehouseItem))
            If value IsNot Me._items Then
                Me._items = value
                Me.OnPropertyChanged("Items")
            End If
        End Set
    End Property
    Public Property Count() As Integer
        Get
            Return Me._count
        End Get
        Set(ByVal value As Integer)
            If value <> Me._count Then
                Me._count = value
                Me.OnPropertyChanged("Count")
            End If
        End Set
    End Property

    Protected Overridable Sub OnPropertyChanged(ByVal args As PropertyChangedEventArgs)
        Dim handler As PropertyChangedEventHandler = Me.PropertyChangedEvent
        If handler IsNot Nothing Then
            handler(Me, args)
        End If
    End Sub

    Private Sub OnPropertyChanged(ByVal propertyName As String)
        Me.OnPropertyChanged(New PropertyChangedEventArgs(propertyName))
    End Sub

    Public Event PropertyChanged As PropertyChangedEventHandler Implements INotifyPropertyChanged.PropertyChanged
End Class

Here is an example class that dynamically creates the sample data.

Example 4: Create Sample Data

public class WarehouseService
{
    public static ObservableCollection<WarehouseItem> GetWarehouseData()
    {
        ObservableCollection<WarehouseItem> data = new ObservableCollection<WarehouseItem>();
        WarehouseItem drinks = new WarehouseItem( "Drinks", 35 );
        drinks.Items.Add( new WarehouseItem( "Water", 10 ) );
        WarehouseItem tea = new WarehouseItem( "Tea", 20 );
        tea.Items.Add( new WarehouseItem( "Black", 10 ) );
        tea.Items.Add( new WarehouseItem( "Green", 10 ) );
        drinks.Items.Add( tea );
        drinks.Items.Add( new WarehouseItem( "Coffee", 5 ) );
        data.Add( drinks );
        WarehouseItem vegetables = new WarehouseItem( "Vegeatbles", 75 );
        vegetables.Items.Add( new WarehouseItem( "Tomato", 40 ) );
        vegetables.Items.Add( new WarehouseItem( "Carrot", 25 ) );
        vegetables.Items.Add( new WarehouseItem( "Onion", 10 ) );
        data.Add( vegetables );
        WarehouseItem fruits = new WarehouseItem( "Fruits", 55 );
        fruits.Items.Add( new WarehouseItem( "Cherry", 30 ) );
        fruits.Items.Add( new WarehouseItem( "Apple", 20 ) );
        fruits.Items.Add( new WarehouseItem( "Melon", 5 ) );
        data.Add( fruits );
        return data;
    }
}
Public Class WarehouseService
 Public Shared Function GetWarehouseData() As ObservableCollection(Of WarehouseItem)
  Dim data As New ObservableCollection(Of WarehouseItem)()
  Dim drinks As New WarehouseItem("Drinks", 35)
  drinks.Items.Add(New WarehouseItem("Water", 10))
  Dim tea As New WarehouseItem("Tea", 20)
  tea.Items.Add(New WarehouseItem("Black", 10))
  tea.Items.Add(New WarehouseItem("Green", 10))
  drinks.Items.Add(tea)
  drinks.Items.Add(New WarehouseItem("Coffee", 5))
  data.Add(drinks)
  Dim vegetables As New WarehouseItem("Vegeatbles", 75)
  vegetables.Items.Add(New WarehouseItem("Tomato", 40))
  vegetables.Items.Add(New WarehouseItem("Carrot", 25))
  vegetables.Items.Add(New WarehouseItem("Onion", 10))
  data.Add(vegetables)
  Dim fruits As New WarehouseItem("Fruits", 55)
  fruits.Items.Add(New WarehouseItem("Cherry", 30))
  fruits.Items.Add(New WarehouseItem("Apple", 20))
  fruits.Items.Add(New WarehouseItem("Melon", 5))
  data.Add(fruits)
  Return data
 End Function
End Class

Finally, define a view model containing the created sample data.

Example 5: Define a Sample View Model

public class WarehouseViewModel: ViewModelBase
{
    private ObservableCollection<WarehouseItem> warehouseItems;

    public ObservableCollection<WarehouseItem> WarehouseItems 
    {
        get 
        {
            if (this.warehouseItems == null)
            {
                this.warehouseItems = WarehouseService.GetWarehouseData();
            }

            return this.warehouseItems;
        }
    }
}
Public Class WarehouseViewModel
    Inherits ViewModelBase

    Private _warehouseItems As ObservableCollection(Of WarehouseItem)

    Public ReadOnly Property WarehouseItems() As ObservableCollection(Of WarehouseItem)
        Get
            If Me._warehouseItems Is Nothing Then
                Me._warehouseItems = WarehouseService.GetWarehouseData()
            End If

            Return Me._warehouseItems
        End Get
    End Property
End Class

In order to display your data, you need to bind the ItemsSource property of RadTreeListView.

Example 6: Bind RadTreeListView

<Window.Resources>
    <my:WarehouseViewModel x:Key="MyViewModel"/>
</Window.Resources>
<telerik:RadTreeListView DataContext="{StaticResource MyViewModel}" 
                         x:Name="radTreeListView"
                         ItemsSource="{Binding WarehouseItems}"/>

At this point, only the first level of the hierarchical data will get displayed and RadTreeListView will look just like a RadGridView.

Figure 1: RadTreeListView bound to collection of WarehouseItems

In order to display the other levels of the hierarchy, you have to define a TreeListViewTableDefinition and set its ItemsSource property to the respective member of the business object. Then you need to set the table definition to the ChildTableDefinition property of RadTreeListView.

In the context of RadTreeListView control, you shouldn't use the GridViewTabelDefinition class, but instead use the TreeListViewTableDefinition class because it exposes an ItemSource property that should be bound to the property that represents the next level of hierarchy. This property should have the same name at each level of the hierarchy.

Example 7: Define a ChildTableDefinition for RadTreeListView

<telerik:RadTreeListView x:Name="radTreeListView"
                            ItemsSource="{Binding WarehouseItems}">
    <telerik:RadTreeListView.ChildTableDefinitions>
        <telerik:TreeListViewTableDefinition ItemsSource="{Binding Items}" />
    </telerik:RadTreeListView.ChildTableDefinitions>
</telerik:RadTreeListView>

Columns

By default, RadTreeListView will auto-generate the columns for its data by creating a column for each property. In order to prevent this, you must set the AutogenerateColumns property to False and manually add the desired columns to the Columns collection of the control.

Example 8: Manually Define the Columns of RadTreeListView

<telerik:RadTreeListView x:Name="radTreeListView"
                            AutoGenerateColumns="False"
                ItemsSource="{Binding WarehouseItems}">
    <telerik:RadTreeListView.ChildTableDefinitions>
        <telerik:TreeListViewTableDefinition ItemsSource="{Binding Items}" />
    </telerik:RadTreeListView.ChildTableDefinitions>
    <telerik:RadTreeListView.Columns>
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}"
                                    Header="Name" />
        <telerik:GridViewDataColumn DataMemberBinding="{Binding Count}"
                                    Header="Count" />
    </telerik:RadTreeListView.Columns>
</telerik:RadTreeListView>

RadTreeListView can use the same column types used with RadGridView. To learn more about the different types of columns, read here.

To change the column, which holds the tree view UI, use the HierarchyColumnIndex property.

Figure 2 shows a snapshot of the result.

Figure 2: RadTreeListView with manually defined columns

See Also