All posts

Asynchronous Master-Details with RadGridView for Silverlight and WCF RIA Services

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!

Facebook Twitter DZone It! Digg It! StumbleUpon Technorati Del.icio.us NewsVine Reddit Blinklist Add diigo bookmark

Comments  6

  • 08 Jan

    Rossen, I can't believe you used Flash to demo Silverlight app. :-))

    Nice!
    ..Ben

    Ben Hayat

  • 08 Jan

    Hello Ben,

    Jing was the easiest tool for me to use since I was in a great hurry.

    Rossen Hristov

  • 08 Jan

    Hi Rossen;

    Sorry if it came out the wrong way. I agree with you. I was sort of making a point how odd it is that in many cases we have to use "Flash" (a competing product) to show SL product. Even MSFT had done it and got lots of heat for that.

    Again, excellent blog [as always]!

    Ben Hayat

  • 08 Jan

    Hello Ben,

    I totally agree with you. I was just pressed by time to publish my blog and that is why I used Jing, which by the way is a great piece of software.

    Actually, I am always using it when I have to communicate with our customers in support tickets or forum threads. You know that time matters in these cases. Sometimes words and code are just not enough, you have to see the action live. And when you want to send that response as soon as possible, Jing helps a lot. Long story short, it is just great. I just love the "Capture -> Publish -> Paste the Link" workflow. It saves a massive amount of time when you want to get that message delivered as soon as possible.

    To tell you the truth, minutes after I read your comment I have noticed that the videos in my two blog posts were no longer available. I guess that they have reached some kind of maximum bandwidth limit, and since I was using the free version of Jing (I have to admit) they were no longer available, which is quite normal and expected.

    For now I have migrated the two videos to YouTube, so that the integrity of the two posts stays intact and readers can actually see something until I come up with another alternative.

    I am considering Silverlight Streaming for my future video needs. I think that this will drop the last piece of the puzzle in place. What do you think?

    Rossen Hristov

  • 08 Jan

    I am considering Silverlight Streaming for my future video needs. I think that this will drop the last piece of the puzzle in place. What do you think?

    As much as I hate to say this, but I have to admit it. Flash in many ways is far more advance and more  mature than SL. Even though I joked with you why you're not using SL, but the reality is that Flash does certain things, that SL may never get to. [ A long discussion I had with Valio on this].
    In some cases like above, sometimes is best to use what's best regardless of what technology it is, just to get the job done.
    However, there is flip side to this. In your case, as employee of a company that specializes in MSFT product, particularly a vendor that is # 1 in SL, looks odd in the eyes of an outsider to see Telerik is using Flash. I just recently had this talk with Robert about Telerik.TV. Yes, it does a great job, but it gives a wrong message...

    This reminds of a story that a few years ago, when Afghan people were fighting Soviet Union, they were looking to buy and use Russian arms to fight the Russians. Why, because they knew the Russian arms are the best and gets the job done. Now we are using Flash to fight Adobe... :-))

    ..Ben

    Ben Hayat

  • 08 Jan

    Hello Ben,

    The Silverlight platform is developing so rapidly, and I am quite sure that soon enough we will be able to embrace in its full extent. 2010 and Silverlight 4 will be very important for the Silverlight community, without any doubt.

    Also, I do not think that different technologies have to fight each other. They can work together.

    As an example, Microsoft SQL Server Reporting Services and Telerik Reporting are both capable of exporting to Adobe's PDF file format. PDF is just popular and that is why it is supported by both products. Various technologies and platforms can work closely together in order to deliver a final product and I do not see anything wrong in that.

    Rossen Hristov

Post a comment
  1. Formatting options
       
     
     
     
     
       
  2. Security image