Binding to WCF Service

The purpose of this tutorial is to show you how to populate a RadTreeView with data from a WCF Service.

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

Here will be examined "best practice" for using RadTreeView with load on demand and WCF 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 treeview 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 WCF Service

  • In the NorthwindDataSource class add a reference to an ObservableCollection of Categories.
  • In the NorthwindDataSource class add a reference to your WCF Service client:

        public class NorthwindDataSource 
        { 
            private SampleWcfServiceClient serviceClient; 
            public NorthwindDataSource() 
            { 
                serviceClient = new SampleWcfServiceClient(); 
                this.Categories = new ObservableCollection<Categories>(); 
            } 
            public ObservableCollection<Categories> Categories 
            { 
                get; 
                set; 
            } 
        } 
    
        Public Class NorthwindDataSource 
            Private serviceClient As SampleWcfServiceClient 
     
            Public Sub New() 
                serviceClient = New SampleWcfServiceClient() 
                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 
        End Class 
    
  • Add the following code in the constructor of the NorthwindDataSource. It will make the initial load of all Categories from the database:

        this.serviceClient.LoadCategoriesCompleted += new EventHandler<LoadCategoriesCompletedEventArgs>( serviceClient_LoadCategoriesCompleted ); 
        this.serviceClient.LoadCategoriesAsync(); 
    

        foreach ( Categories c in serviceClient.LoadCategories() ) 
        { 
            this.Categories.Add( c ); 
        } 
    
        For Each c As Categories In serviceClient.LoadCategories() 
            Me.Categories.Add(c) 
        Next 
    
        AddHandler Me.serviceClient.LoadCategoriesCompleted, AddressOf serviceClient_LoadCategoriesCompleted 
        Me.serviceClient.LoadCategoriesAsync() 
    

    And here is the code handling the __LoadCategoriesCompleted__event:

        private void serviceClient_LoadCategoriesCompleted( object sender, LoadCategoriesCompletedEventArgs e ) 
        { 
            if ( e.Error == null && e.Result != null ) 
            { 
                foreach ( Categories c in e.Result ) 
                { 
                    this.Categories.Add( c ); 
                } 
            } 
        } 
    
        Private Sub serviceClient_LoadCategoriesCompleted(ByVal sender As Object, ByVal e As LoadCategoriesCompletedEventArgs) 
            If e.[Error] Is Nothing AndAlso e.Result IsNot Nothing Then 
                For Each c As Categories In e.Result 
                    Me.Categories.Add(c) 
                Next 
            End If 
        End Sub 
    

    The body of the exposed LoadCategories() method is shown on the code snippet below.

        [OperationContract] 
        public List<Categories> LoadCategories() 
        { 
            NorthwindEntities ent = new NorthwindEntities(); 
            return ent.Categories.Execute( MergeOption.AppendOnly ).ToList(); 
        } 
    
        <OperationContract> 
        Public Function LoadCategories() As List(Of Categories) 
            Dim ent As New NorthwindEntities() 
            Return ent.Categories.Execute(MergeOption.AppendOnly).ToList() 
        End Function 
    
  • 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 treeview structure.

        <DataTemplate x:Key="ProductTemplate"> 
            <TextBlock Text="{Binding ProductName}" /> 
        </DataTemplate> 
        <telerik:HierarchicalDataTemplate x:Key="CategoryTemplate" ItemsSource="{Binding Products}" 
          ItemTemplate="{StaticResource ProductTemplate}"> 
            <TextBlock Text="{Binding CategoryName}" /> 
        </telerik:HierarchicalDataTemplate> 
    
  • Update your treeview 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: Silverlight RadTreeView Binding to WCF Service Data

    If you try to expand any of the loaded categories, the default load on demand animation will be started: Silverlight 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 void BeginLoadingProducts( Categories category ) 
        { 
            serviceClient.LoadProductsByCategoryIdCompleted += new EventHandler<LoadProductsByCategoryIdCompletedEventArgs>( serviceClient_LoadProductsByCategoryIdCompleted ); 
            serviceClient.LoadProductsByCategoryIdAsync( category.CategoryID, category ); 
        } 
        private void serviceClient_LoadProductsByCategoryIdCompleted( object sender, LoadProductsByCategoryIdCompletedEventArgs e ) 
        { 
            if ( e.Error == null && e.Result != null ) 
            { 
                Categories currentCategory = e.UserState as Categories; 
                foreach ( Products p in e.Result ) 
                { 
                    currentCategory.Products.Add( p ); 
                } 
            } 
        } 
    

        public void LoadProducts( Categories category ) 
        { 
            category.Products = new ObservableCollection<Products>(); 
            foreach ( Products p in serviceClient.LoadProductsByCategoryId( category.CategoryID ) ) 
            { 
                category.Products.Add( p ); 
            } 
        } 
    
        Public Sub LoadProducts(ByVal category As Categories) 
            category.Products = New ObservableCollection(Of Products)() 
            For Each p As Products In serviceClient.LoadProductsByCategoryId(category.CategoryID) 
                category.Products.Add(p) 
            Next 
        End Sub 
    
        Public Sub BeginLoadingProducts(ByVal category As Categories) 
            AddHandler serviceClient.LoadProductsByCategoryIdCompleted, AddressOf serviceClient_LoadProductsByCategoryIdCompleted 
            serviceClient.LoadProductsByCategoryIdAsync(category.CategoryID, category) 
        End Sub 
        Private Sub serviceClient_LoadProductsByCategoryIdCompleted(ByVal sender As Object, ByVal e As LoadProductsByCategoryIdCompletedEventArgs) 
            If e.[Error] Is Nothing AndAlso e.Result IsNot Nothing Then 
                Dim currentCategory As Categories = TryCast(e.UserState, Categories) 
                For Each p As Products In e.Result 
                    currentCategory.Products.Add(p) 
                Next 
            End If 
        End Sub 
    

    The body of the exposed LoadProductsByCategoryId() method is shown on the code snippet below.

        [OperationContract] 
        public List<Products> LoadProductsByCategoryId( int categoryId ) 
        { 
            NorthwindEntities ent = new NorthwindEntities(); 
            var q = from p in ent.Products 
                    where p.Categories.CategoryID == categoryId 
                    orderby p.ProductName 
                    select p; 
            return q.ToList(); 
        } 
    
        <OperationContract> 
        Public Function LoadProductsByCategoryId(categoryId As Integer) As List(Of Products) 
            Dim ent As New NorthwindEntities() 
            Dim q = From p In ent.Products Where p.Categories.CategoryID = categoryIdOrder By p.ProductNamep 
            Return q.ToList() 
        End Function 
    
  • 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 ) 
            { 
                ( this.Resources[ "DataSource" ] as 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 
                TryCast(Me.Resources("DataSource"), 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: Silverlight RadTreeView Bound to WCF Service Data

See Also

In this article