Inspired by Brad Abrams’ marvelous series of blog posts, I have decided to create a simple project demonstrating how to harness the enormous power of RIA Services with Telerik RadGridView for Silverlight. I have decided to use the new Chinook database after reading this wonderful post by Tim Heuer explaining how to work with relational data in the RIA Services paradigm. Make sure you have this database installed on the default instance of your SQL Server 2008 Express or you will have to modify the connection string as needed.

In one of my previous blog posts I have thoroughly explained How To Display Hierarchical Data with Row Details. Understanding Row Details is a must before you can go on.

So let’s get going.

1. Create a new Silverlight Application called MasterDetailsWithRIAServices. Host the Silverlight application in a new ASP.NET Web Application and enable .NET RIA Services.

2. In the ASP.NET Web Application create a new folder named Models.

3. Add a new “ADO.NET Entity Data Model” called “ChinookModel” to the Models folder. You can use all kinds of other models, but I decided to go with an Entity Framework model.

4. Select “Generate from database” and connect to the instance where you have installed the Chinook database. Save the entity connection settings as “ChinookEntities”.

5. Select the Album and Artist tables. The model namespace should read “Chinook Model’. The designer will then open and you should see something like this:

ChinookModel

6. Rebuild the solution.

7. In the ASP.NET Web Application create a new folder named Services.

8. Add a new “Domain Service Class” and call it “Chinook Service”.

9. Choose the “ChinookEntities” DataContext. For this demo we won’t need editing and metadata classes:

ChinookService

10. Clicking OK will generate ChinookService.cs in the Services folder.

11. Entity Framework has some weird ways of naming the generated classes so I have renamed the query methods to be in plural form, i.e. GetArtists instead of GetArtist.

12. Since we are doing a master-details demo let’s add another query method that will return all albums given the id of the artist:

Master-Details Query
  1. public IQueryable<Album> GetAlbumsForArtistId(int artistId)
  2. {
  3.     return this.ObjectContext.Album.Where(album => album.Artist.ArtistId == artistId);
  4. }

 

13. Rebuild the solution and let’s go to the client project.

14. Add references to the following Telerik assemblies:

  • Telerik.Windows.Controls
  • Telerik.Windows.Controls.GridView
  • Telerik.Windows.Controls.Input
  • Telerik.Windows.Data

and to:

  • System.Windows.Controls.Ria
  • System.Windows.Data

* You can either download the “Latest Internal Build” version of RadControls for Silverlight from your Client.NET or use the assemblies from the source code archive I have provided.

15. In the client project add a new class called ArtistIdToAlbumCollectionConverter. This is where the magic will happen. This converter creates a new DomainDataSource with the query “GetAlbumsForArtistId” we have created earlier, passes in the artistId parameter and calls the Load method of the DomainDataSource. Finally it returns the DataView which populates the details grid asynchronously:

MainPage
  1. using System;
  2. using System.Net;
  3. using System.Windows;
  4. using System.Windows.Controls;
  5. using System.Windows.Documents;
  6. using System.Windows.Ink;
  7. using System.Windows.Input;
  8. using System.Windows.Media;
  9. using System.Windows.Media.Animation;
  10. using System.Windows.Shapes;
  11. using System.Windows.Data;
  12. using MasterDetailsWithRIAServices.Web.Services;
  13.  
  14. namespace MasterDetailsWithRIAServices
  15. {
  16.     public class ArtistIdToAlbumCollectionConverter : IValueConverter
  17.     {
  18.         public object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  19.         {
  20.             DomainDataSource albumsDataSource = new DomainDataSource()
  21.             {
  22.                 DomainContext = new ChinookContext(),            // Our context
  23.                 AutoLoad = false,                                // We will call Load a little bit later
  24.                 QueryName = "GetAlbumsForArtistIdQuery",        // This is the master-details query from ChinookService.cs
  25.                 LoadSize = 1,                                    // Slow things down artificially to see the asynchronous loading in action
  26.                 LoadInterval = new TimeSpan(0, 0, 0, 0, 100)    // Slow things down artificially to see the asynchronous loading in action
  27.             };
  28.  
  29.             int artistId = (int)value;
  30.             // I want only the albums for this particular artist.
  31.             albumsDataSource.QueryParameters.Add(new Parameter { ParameterName = "artistId", Value = artistId });
  32.  
  33.             albumsDataSource.Load();
  34.  
  35.             // albumsDataSource.DataView implements INotifyCollection and that is
  36.             // how the details grid is populated asynchronously.
  37.             return albumsDataSource.DataView;
  38.         }
  39.  
  40.         public object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
  41.         {
  42.             throw new NotImplementedException();
  43.         }
  44.     }
  45. }

 

16. Now let’s use this converter. We will bind the ItemsSource of the details (albums) grid residing inside the RowDetailsTemplate to the ArtistId and let the converter do the rest of the job for us. Here is what the main page should look like at the end:

MainPage
  1. <UserControl
  2.     x:Class="MasterDetailsWithRIAServices.MainPage"
  3.     xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
  4.     xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
  5.     xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
  6.     xmlns:my="clr-namespace:MasterDetailsWithRIAServices"
  7.     xmlns:riaControls="clr-namespace:System.Windows.Controls;assembly=System.Windows.Controls.Ria"
  8.     xmlns:services="clr-namespace:MasterDetailsWithRIAServices.Web.Services"
  9.     xmlns:telerik="clr-namespace:Telerik.Windows.Controls;assembly=Telerik.Windows.Controls.GridView"
  10.     xmlns:telerikGrid="clr-namespace:Telerik.Windows.Controls.GridView;assembly=Telerik.Windows.Controls.GridView"
  11.     xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
  12.     Width="700"
  13.     d:DesignHeight="480"
  14.     d:DesignWidth="640"
  15.     mc:Ignorable="d">
  16.     <Grid x:Name="LayoutRoot">
  17.         <Grid.Resources>
  18.  
  19.             <!--This is the magic converter. It will take the ArtistId and
  20.             create a DomainDataSource to asynchronously retrieve all
  21.             albums for the given ArtistId.-->
  22.             <my:ArtistIdToAlbumCollectionConverter x:Key="ArtistIdToAlbumCollectionConverter"/>
  23.  
  24.             <!-- RowDetailsTemplate containing the details (albums) grid. -->
  25.             <DataTemplate x:Key="AlbumsTemplate">
  26.                 <Grid Width="500" HorizontalAlignment="Left" Margin="24,2,2,2">
  27.                     <Grid.RowDefinitions>
  28.                         <RowDefinition Height="Auto"/>
  29.                         <RowDefinition/>
  30.                     </Grid.RowDefinitions>
  31.                     <TextBlock Grid.Row="0" Margin="2">Albums:
  32.                     </TextBlock>
  33.                     <!--Bind the albums grid to the ArtistId and let the converter
  34.                     return all albums asynchronously. -->
  35.                     <telerik:RadGridView
  36.                         Name="albumsGrid"
  37.                         ItemsSource="{Binding ArtistId, Converter={StaticResource ArtistIdToAlbumCollectionConverter}}"
  38.                         Grid.Row="1"
  39.                         Margin="2"
  40.                         AutoGenerateColumns="False"
  41.                         ColumnWidth="*"
  42.                         ShowGroupPanel="False">
  43.                         <telerik:RadGridView.Columns>
  44.                             <telerik:GridViewDataColumn Header="Album Title"
  45.                                                         DataMemberBinding="{Binding Title}"/>
  46.                         </telerik:RadGridView.Columns>
  47.                     </telerik:RadGridView>
  48.                 </Grid>
  49.             </DataTemplate>
  50.         </Grid.Resources>
  51.  
  52.         <!-- This is where the master (artists) grid gets its data from. -->
  53.         <riaControls:DomainDataSource x:Name="artistsDataSource"
  54.                                       AutoLoad="True"
  55.                                       QueryName="GetArtistsQuery">
  56.             <riaControls:DomainDataSource.DomainContext>
  57.                 <services:ChinookContext/>
  58.             </riaControls:DomainDataSource.DomainContext>
  59.         </riaControls:DomainDataSource>
  60.  
  61.         <telerik:RadGridView
  62.             Name="artistsGrid"
  63.             ItemsSource="{Binding ElementName=artistsDataSource, Path=Data}"
  64.             IsBusy="{Binding ElementName=artistsDataSource, Path=IsBusy}"
  65.             RowDetailsTemplate="{StaticResource AlbumsTemplate}"
  66.             ColumnWidth="*"
  67.             AutoGenerateColumns="False"
  68.             ShowGroupPanel="False">
  69.             <telerik:RadGridView.Columns>
  70.                 <telerik:GridViewToggleRowDetailsColumn/>
  71.                 <telerik:GridViewDataColumn DataMemberBinding="{Binding Name}" Header="Artist"/>
  72.             </telerik:RadGridView.Columns>
  73.         </telerik:RadGridView>
  74.     </Grid>
  75. </UserControl>

17. Build and run. Click on any of the row details toggle buttons.

Notice how the albums are retrieved asynchronously. Since you will be running this demo on your local machine, I have manually “slowed down” the connection so you can see what is really going on. For the master grid I have used Brad Abrams’ “hotel internet connection”© approach and for the details grid I have configured the DomainDataSource to pull data slowly.

Also, notice that when you click on a row that was already expanded, the data was cached and the row details appear immediately.

Now, let’s see what are my favorite albums, shall we:

 

You got to love RIA Services.

Here is the full source code of the demo. Enjoy!


About the Author

Rossen Hristov

 is Senior Software Developer in Telerik XAML Team

Comments

Comments are disabled in preview mode.