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

Binding to ADO.NET Data Service

The purpose of this tutorial is to show you how to populate a RadTreeView with data from an ADO.NET Data Service.

This tutorial will use the Northwind database, which can be downloaded from here.

Here will be also examined "best practice" for using RadTreeView with load on demand and ADO.NET Data Service. You can read more information about the load on demand behavior here.

  • Add a new RadTreeView declaration in your XAML and add an event handler for LoadOnDemand event. Also set the following properties to True:

    • IsLoadOnDemandEnabled
    • IsExpandOnSingleClickEnabled

        <telerik:RadTreeView x:Name="radTreeView" Margin="8" 
            IsLoadOnDemandEnabled="True" IsExpandOnSingleClickEnabled="True" 
            LoadOnDemand="radTreeView_LoadOnDemand"/> 
    

    The RadTreeView will be bound to a data source object, that has a property Categories. When the LoadOnDemand event of RadTreeView is fired, the selected category asynchronously loads its related products.

  • Create a new class named NorthwindDataSource.

        public class NorthwindDataSource 
        { 
        } 
    
        Public Class NorthwindDataSource 
        End Class 
    
  • Add a reference to your ADO.NET Data Service.

  • In the NorthwindDataSource class add a reference to an ObservableCollection of Categories.

  • In the NorthwindDataSource class add a reference to the NorthwindEntities object:

        private NorthwindEntities northwindEntity; 
     
        public NorthwindDataSource() 
        { 
            this.northwindEntity = new NorthwindEntities( new Uri( "Enter your service address here" ) ); 
            this.Categories = new ObservableCollection<Categories>(); 
        } 
     
        public ObservableCollection<Categories> Categories 
        { 
            get; 
            set; 
        } 
    
        Private northwindEntity As NorthwindEntities 
     
        Public Sub New() 
            Me.northwindEntity = New NorthwindEntities(New Uri("Enter your service address here")) 
            Me.Categories = New ObservableCollection(Of Categories)() 
        End Sub 
     
        Private _Categories As ObservableCollection(Of Categories) 
     
        Public Property Categories() As ObservableCollection(Of Categories) 
            Get 
                Return _Categories 
            End Get 
            Set(ByVal value As ObservableCollection(Of Categories)) 
                _Categories = value 
            End Set 
        End Property 
    
  • Add the following code in the constructor of the NorthwindDataSource. It will make the initial load of all Categories from the database:

        northwindEntity.Categories.BeginExecute( 
            ( IAsyncResult result ) => EntitiesLoaded<Categories>( result, this.Categories ), 
            northwindEntity.Categories ); 
    

        foreach ( Categories c in northwindEntity.Categories.Execute() ) 
        { 
            this.Categories.Add( c ); 
        } 
    
        For Each c As Categories In northwindEntity.Categories.Execute() 
            Me.Categories.Add(c) 
        Next 
    
        northwindEntity.Categories.BeginExecute(Function(ByVal result As IAsyncResult) EntitiesLoaded(Of Categories)(result, Me.Categories), northwindEntity.Categories) 
    

        private static void EntitiesLoaded<T>( IAsyncResult result, Collection<T> entities ) 
        { 
            DataServiceQuery<T> query = result.AsyncState as DataServiceQuery<T>; 
            foreach ( T entity in query.EndExecute( result ) ) 
            { 
                entities.Add( entity ); 
            } 
        } 
    
        Private Shared Sub EntitiesLoaded(Of T)(ByVal result As IAsyncResult, ByVal entities As Collection(Of T)) 
            Dim query As DataServiceQuery(Of T) = TryCast(result.AsyncState, DataServiceQuery(Of T)) 
            For Each entity As T In query.EndExecute(result) 
                entities.Add(entity) 
            Next 
        End Sub 
    

    Since the first load of the categories is also asynchronous, it takes some time to display the treeview for the first time. You may consider adding some loading animation in your application.

  • Declare the NorthwindDataSource object as a resource in your application.

        <UserControl.Resources> 
            <example:NorthwindDataSource x:Key="DataSource"/> 
        </UserControl.Resources> 
    
  • Declare HierarchicalDataTemplates which will describe the RadTreeView structure.

        <DataTemplate x:Key="ProductTemplate"> 
            <TextBlock Text="{Binding ProductName}" /> 
        </DataTemplate> 
        <HierarchicalDataTemplate x:Key="CategoryTemplate" ItemsSource="{Binding Products}" 
            ItemTemplate="{StaticResource ProductTemplate}"> 
            <TextBlock Text="{Binding CategoryName}" /> 
        </HierarchicalDataTemplate> 
    
  • Update your RadTreeView declaration - set the ItemsSource and ItemTemplate properties.

        <telerik:RadTreeView x:Name="radTreeView" Margin="8" 
            IsLoadOnDemandEnabled="True" IsExpandOnSingleClickEnabled="True" 
            LoadOnDemand="radTreeView_LoadOnDemand" 
            ItemTemplate="{StaticResource CategoryTemplate}" 
            ItemsSource="{Binding Source={StaticResource DataSource}, Path=Categories}"/> 
    

    Run your demo, the result can be seen on the next picture: WPF RadTreeView Binding to ADO NET Data

    If you try to expand any of the loaded categories, the default load on demand animation will be started: WPF RadTreeView Load On Demand Animation

The next step is to handle the load on demand event.

  • Add the following method to the NorthwindDataSource class, which aims to load the products for the expanded category:

        public static void BeginLoadingProducts( Categories category ) 
        { 
            DataServiceQuery<Products> categoryProducts = northwindEntity 
                .CreateQuery<Products>( string.Format( "Categories({0})/Products", category.CategoryID ) ) 
                .Expand( "Suppliers" ) 
                .Expand( "Categories" ); 
            categoryProducts.BeginExecute( 
                ( IAsyncResult result ) => EntitiesLoaded<Products>( result, category.Products ), 
                categoryProducts ); 
        } 
    

        public static void LoadProducts( Categories category ) 
        { 
            DataServiceQuery<Products> categoryProducts = northwindEntity 
                .CreateQuery<Products>( string.Format( "Categories({0})/Products", category.CategoryID ) ) 
                .Expand( "Suppliers" ) 
                .Expand( "Categories" ); 
            category.Products = new ObservableCollection<Products>(); 
            foreach ( Products p in categoryProducts.Execute() ) 
            { 
                category.Products.Add( p ); 
            } 
        } 
    
        Public Shared Sub LoadProducts(ByVal category As Categories) 
            Dim categoryProducts As DataServiceQuery(Of Products) = northwindEntity.CreateQuery(Of Products)(String.Format("Categories({0})/Products", category.CategoryID)).Expand("Suppliers").Expand("Categories") 
     
            category.Products = New ObservableCollection(Of Products)() 
            For Each p As Products In categoryProducts.Execute() 
                category.Products.Add(p) 
            Next 
        End Sub 
    
        Public Shared Sub BeginLoadingProducts(ByVal category As Categories) 
            Dim categoryProducts As DataServiceQuery(Of Products) = northwindEntity.CreateQuery(Of Products)(String.Format("Categories({0})/Products", category.CategoryID)).Expand("Suppliers").Expand("Categories") 
     
            categoryProducts.BeginExecute(Function(ByVal result As IAsyncResult) EntitiesLoaded(Of Products)(result, category.Products), categoryProducts) 
        End Sub 
    
  • Add the following code to the load on demand event handler, which you declared on step 1.

        private void radTreeView_LoadOnDemand( object sender, Telerik.Windows.RadRoutedEventArgs e ) 
        { 
            RadTreeViewItem item = e.OriginalSource as RadTreeViewItem; 
            Categories category = item.Item as Categories; 
            if ( category != null ) 
            { 
                NorthwindDataSource.BeginLoadingProducts( category ); 
            } 
            else 
            { 
                item.IsLoadOnDemandEnabled = false; 
            } 
        } 
    
        Private Sub radTreeView_LoadOnDemand(ByVal sender As Object, ByVal e As Telerik.Windows.RadRoutedEventArgs) 
            Dim item As RadTreeViewItem = TryCast(e.OriginalSource, RadTreeViewItem) 
     
            Dim category As Categories = TryCast(item.Item, Categories) 
            If category IsNot Nothing Then 
                NorthwindDataSource.BeginLoadingProducts(category) 
            Else 
                item.IsLoadOnDemandEnabled = False 
            End If 
        End Sub 
    

    When there are no items to add, and you want to prevent the LoadOnDemand event to fire again, set the IsLoadOnDemandEnabled property to False to the RadTreeViewItem that has fired the LoadOnDemand event.

And here is the result: WPF RadTreeView Binding to Northwind Data Source

See Also

In this article