Master pages, part VI. Progressive download with web service, datagrid, etc. : declaratively specifying downloadable modules

by gleblanc 28. March 2009 18:37

Let's see how to declaratively specify all modules (XAP files, images, etc.) that we decide to load asynchronously in order to reduce wait time for the user.

Our application is made of a master page, a first page (initially displayed with the master page) and a second page, downloaded asynchronously. In the first page, we have a datagrid that gets its data from a web service. Due to the heavy footprint of the datagrid, we will also load it asynchronously.

I am afraid only veterans among the veterans read one day the books mentionned here (you can click on items and get info in tooltips). Believe it or not, there was a time when "serious" programmers (those working in PL/I and CICS on 360/370 mainframes) considered PCs as toys without any future. Reading these books was considered as politically incorrect in the very very large, air-conditioned, computer rooms with very large windows, just near the main entrance (people were so proud to work there!). Background images are paintings from Piet Mondrian (Mondriaan before he decided to americanize his name).


Project / source code

We first build the Web Service (here an Asmx web service), named BooksWS, in the Web part of the solution. Nothing new and in relation with this post : since the web service is executed on the server, it is not downloaded to the client.

The initial project (SilverlightApplication6) contains the master page. In this project, we add Page1 (Page1.xaml). In the solution, we create a project for Page2 (Proj4Page2), a project to hold data common to the different pages (Proj4Data), a project for the datagrid (Proj4DataGrid) and a project to refer to the web service (Proj4UseBooksWS). Five XAP files are thus created in the ClientBin folder. Four of them will be downloaded asynchronously, as well as background images, other images and some text information. The initial XAP file is only 22 KB and will thus be displayed quickly.

Let's come to the part that presents interest : declaratively specifying the modules that have to be downloaded asynchronously (though in sequence).

In the initial project, we add a class named Action :

 public class Action
 {
  public delegate void Del(OpenReadCompletedEventArgs e);
  public string File { get; set; }
  public Del Fct { get; set; }
  public object Dest { get; set; }
  public string Comment { get; set; }
 }

We will later on create an array of actions. In an Action item, we specify : 
- File : the name of what has to be downloaded (for instance Proj4Page2.xap or myImage.jpg),
- Dest : the destination (a page, an image somewhere or whatever you decide) ,
- Fct : the function (you have to write it) to be executed when the client gets the data (it's a delegate, in other words a pointer to a function that gets as parameter information on the asynchronous read at completion time),
- Comment : a comment used here to display information in the status bar.

In the C# file of the master page (Page.xaml), we build the array of actions (in the constructor) :

 List<Action> actions;
 .....
 actions = new List<Action>() {
    new Action(){File="Mondrian1.jpg", Fct=new Action.Del(LoadImage),
       Dest=0, Comment="Loading background image (Piet Mondrian) for master page..."},
    new Action(){File="Proj4Data.xap", Fct=new Action.Del(LoadPageForData),
       Comment="Loading xap file of project for common values..."},
    .....
  };

At the end of the constructor, we fire the first asynchronous download :
 int nStep = 0;
 .....
 client = new WebClient();
 client.OpenReadCompleted += new OpenReadCompletedEventHandler(client_OpenReadCompleted);
 // start serie of async loads
 client.OpenReadAsync(new Uri(actions[nStep].File, UriKind.Relative));
 stBar.Text = actions[0].Comment;

The client_OpenReadCompleted function becomes :

 void client_OpenReadCompleted(object sender, OpenReadCompletedEventArgs e)
 {
  actions[nStep].Fct(e);
  nStep++;
  if (nStep < actions.Count)
  {
   stBar.Text = actions[nStep].Comment;
   client.OpenReadAsync(new Uri(actions[nStep].File, UriKind.Relative));
  }
  else stBar.Text = "";
 }

Every Fct function is specific to the termination of a specific asynchronous download. For instance, LoadPage2 terminates the asynchronous load of Page2 and is, as seen in a previous post :

 public void LoadPage2(OpenReadCompletedEventArgs e)
 {
  sri = new StreamResourceInfo(e.Result, null);
  sri4dll = Application.GetResourceStream(sri, new Uri("Proj4Page2.dll", UriKind.Relative));
  asmPart = new AssemblyPart();
  asm = asmPart.Load(sri4dll.Stream);
  uc = asm.CreateInstance("Proj4Page2.Page") as UserControl;
  page2 = uc;
 }

The Proj4Data project is directly referenced in other projects : it contains references to common data and is only 4 KB in size. In the Proj4UseBooksWS project, we add a service reference to the web service. After compilation, do not forget to copy the ServiceReferences.ClientConfig file from this project to the project of the master page (here SilverlightApplication6).

See source code, included as usual, for additional information. Enjoy Silverlight !

Tags:

Powered by BlogEngine.NET 1.5.0.7
Theme by Mads Kristensen

About the author

Gerard Leblanc is the author of several books (in french) on C++, C#, .NET and Silverlight (Eyrolles, Paris as publisher). See www.gleblanc.eu as the companion web site for these books (included sample programs).
He is Microsoft MVP for Silverlight.

MVP logo