Skip to content
David Cumps
Pocket PC

Pocket PC

Originally published on my old blog at cumps.be on May 1, 2005.

On the client-side, a Pocket PC application was used. Since this has no guaranteed connectivity, some additional techniques had to be used to improve the end-user experience.

First of all, when calling a web service from a Pocket PC, it was possible that the call would take a long time. If this would have been done synchronously, the application would lock up as long as the call was being processed. To prevent this, the call was made asynchronously and a progress bar was displayed.

To achieve this, a Timer from the System.Threading namespace was used to update the progress bar when it was visible. This made the timer run on a different thread from the application and make callbacks at certain intervals to update the user interface containing the progress bar.

The following code was used to easily start and stop the progress bar:

using System;
using System.Threading;

namespace MediaService.Pocket {
  public class MediaForm : System.Windows.Forms.Form {
    private System.Threading.Timer progressTimer;
    private OpenNETCF.Windows.Forms.ProgressBarEx asyncProgress;
    private System.Windows.Forms.Label asyncLabel;

    public MediaForm(Int32 userId, String authTicket) {
      TimerCallback progressDelegate = new TimerCallback(this.UpdateProgress);
      this.progressTimer = new System.Threading.Timer(progressDelegate, null,
                                          Timeout.Infinite, Timeout.Infinite);
    } /* MediaForm */

    private void StartProgress(ProgressEnum progressType) {
      // Reset progressbar and show
      this.asyncProgress.Value = this.asyncProgress.Minimum;
      this.asyncProgress.Visible = true;
      this.asyncLabel.Visible = true;
      this.asyncLabel.Text = "Retrieving Content";
      this.progressTimer.Change(0, 100);
    } /* StartProgress */

    protected void UpdateProgress(Object state) {
      if (this.asyncProgress.Value + 1 > this.asyncProgress.Maximum) {
        this.asyncProgress.Value = this.asyncProgress.Minimum;
      } else {
        this.asyncProgress.Value++;
      }
    } /* UpdateProgress */

    private void StopProgress() {
      this.progressTimer.Change(Timeout.Infinite, Timeout.Infinite);
      this.asyncProgress.Visible = false;
      this.asyncLabel.Visible = false;
    } /* StopProgress */

After the progress bar was started, an asynchronous call was made to the web service, preventing the application from locking up, using the following syntax:

AsyncCallback callBack = new AsyncCallback(this.OnGetSongs);
IAsyncResult songsResult = this.GetService().BeginGetSongs(callBack, null);

This started the call to the web service on a different thread, and when the web service call finished, it called back to the OnGetSongs method in this case. In this method, the results were retrieved and the user interface was updated.

private void OnGetSongs(IAsyncResult songsResult) {
  this.availableSongsCache = this.GetService().EndGetSongs(songsResult);
  if (this.InvokeRequired()) {
    this.Invoke(new EventHandler(this.UpdateAvailableSongs));
  } else {
    this.UpdateAvailableSongs(this, System.EventArgs.Empty);
  }
} /* OnGetSongs */

It was possible that the callback occurred from a different thread. In that case it was not possible to update the user interface, since the thread did not own the form controls. To detect if the callback occurred on another thread or not, the following code was used:

namespace MediaService.Pocket {
  public class MediaForm : System.Windows.Forms.Form {
    private readonly Thread formThread = Thread.CurrentThread;

    private Boolean InvokeRequired() {
      return !this.formThread.Equals(Thread.CurrentThread);
    } /* InvokeRequired */

If the callback happened on another thread, the Invoke method had to be used to handle the update of the user interface on the thread that owned the interface. For this reason, the method updating the interface had to have the following signature:

private void UpdateAvailableSongs(object sender, EventArgs e) {

At this point, it was possible to make a web service call without locking the user interface, while informing the user that something is going on thanks to the progress bar.

You May Also Like

SQL Server CE

SQL Server CE

Caching web service results in a local SQL Server CE database on the Pocket PC, so data shows instantly and refreshes when needed.

Data Layer

Data Layer

Why every data-driven application benefits from a separate data layer, and how I added one so the data source can be chosen.