Our Blog

Displaying a progress bar while waiting the result of a time-consuming operation in Silverlight

Yavor Valchev
by Yavor Valchev on Thu 17 January 2013 No comments

Sooner or later it happens to everyone that he needs to call a time consuming wcf service. However the good user experience requires that the application does not “hang” waiting for the result of the operation and ideally displays its progress. All of us have used static progress bars that simply block the user from interacting with the application by greying out the whole screen for example. This is a good way to show that the server is busy with the user request and to prevent the user from requesting the same again but it only works if the person has not wait no more than about 10 seconds. If the operation takes longer to complete we’d better think of another type of progress bar.


Let’s say we have a list of user bank accounts and that due to a new tax enforced by the government we have to recalculate the interests of all user deposits for a given period. If we have a Silverlight administration application it will fire a request to the server to do the recalculation and will pass the dates as parameters. To improve user experience we have to return as quickly as possible how many users are going to be affected, to start recalculating each user’s interest and to report progress to the Silverlight client. Reporting progress can be achieved in two ways – by a duplex service (a bit more complex and requires more configurations to be made) or by the Silverlight polling the server each second to report its progress. If we choose the second option we have to load the users, start recalculation of the interests in a separate thread and return a key to the Silverlight application with which it can check the progress of the operation. Then we have the following:

In the Silverlight application – we call the service to recalculate the interests:


void btnRecalculate_Click( object sender, EventArgs e)
{
     Service.RecalculateInterests(pickerFromDate.SelectedDate, pickerToDate.SelectedDate);
}

In the web server:


private static Dictionary;
BulkRecalculateProgress = new Dictionary();
public void RecalculateInterests(DateTime fromDate, DateTime toDate)
{
    var users = GetUsersToRecalculate(fromDate, toDate);
    var guid = Guid.NewGuid();
    BulkRecalculateProgress.Add(guid, new KeyValuePair(0, users.Count));
    BackgroundWorker backgroundWorker = new BackgroundWorker();
    backgroundWorker.DoWork += backgroundWorker_DoWork;
    object[] parameters = {users, guid };
    backgroundWorker.RunWorkerAsync(parameters);
    return guid;
}

Now in the Silverlight client we have a key(the guid) with which we can request the progress of the operation:

In the Silverlight client:


Service_ RecalculateInterestsCompleted(object sender, RecalculateInterestsCompletedEventArgs e)
{
   BulkRecalculateGuid = e.Result;
   Service.GetRecalculateProgressAsync(RecalculateGuid);
   ProgressTimer.Start();
}

The ProgressTimer in the Silverlight client will call the GetRecalculateProgress service every second to check the progress of the operation. When it is over the timer will be stopped:


void ProgressTimer_Tick(object sender, EventArgs e)
{
    Service.GetRecalculateProgressAsync(BulkRecalculateGuid);
}
void Service_GetRecalculateProgressCompleted(object sender, GetRecalculateProgressCompletedEventArgs e)
{
   KeyValuePair progress = e.Result;
   If(progress.Key<progress.Value)
   {
      //Report progress
   }
   else
   {
      ProgressTimer.Stop();
      //Report success
   }
}

At the server side we have the following code:


void backgroundWorker_DoWork(object sender, DoWorkEventArgs e)
{
  var parameters = (object[])e.Argument;
  var users = Listparameters[0];
  var guid = parameters[1];
  var counter = 0;
  foreach(user in users)
  {
     RecalculateUserInterests(user);
     counter++;
     BulkRecalculateProgress[guid] = new KeyValuePair(counter, users.Count);
  }
 }
//This is the service that reports the progress to the Silverlight client
 public KeyValuePair GetRecalculateProgress(Guid guid)
 {
 return BulkRecalculateProgress[guid];
 }
Yavor ValchevDisplaying a progress bar while waiting the result of a time-consuming operation in Silverlight

Related Posts

Take a look at these posts

Join the conversation