The multiple asynchronous method calls in a window Window Phone 7

advertisements

I have a collection of picture Objects for which I need to download thumbs and pictures files located on dataservise, how can I managed this? In this method I have loop to call three methods; one to add objects to data base, second to download and save picture thumb and third to download and save picture file the other two is ClientOpenReadCompleted methods.

public bool AddAllPhoto()
{
  var amount = App.ViewModel.NewPictures.Count;
  for (int i = 0; i < amount; i++)
  {
    //to add picture to DB
    SavePicture(App.ViewModel.NewPictures[i]);

    DownloadPicture(NewPictures[i].ID.ToString());
    DownloadPictureThumb(NewPictures[i].ID.ToString()));
  }

  return true;
}

Second;

public void DownloadPictureThumb(string path)
{
  string outputString = String.Format("http://" + App.ServerAdress + "/ /Pictures/Thumbs/{0}.jpg", path);
  var client = new WebClient();
  client.OpenReadCompleted += ClientOpenReadCompleted1;
  client.OpenReadAsync(new Uri(outputString));
}

private static void ClientOpenReadCompleted1(object sender, OpenReadCompletedEventArgs e)
{
  var resInfo = new StreamResourceInfo(e.Result, null);
  var reader = new StreamReader(resInfo.Stream);

  byte[] contents;
  using (var bReader = new BinaryReader(reader.BaseStream))
  {
    contents = bReader.ReadBytes((int)reader.BaseStream.Length);
  }

  var file = IsolatedStorageFile.GetUserStoreForApplication();

  var thumbFilePath = String.Format(PicturesThumbsColectionKey + "{0}", PictureDataStoreLocal.ID);

  var stream = thumbFile.CreateFile(thumbFilePath);

  stream.Write(contents, 0, contents.Length);
  stream.Close();
}

And third one

public void DownloadPicture(string path)
{
  string outputString = String.Format("http://" + App.ServerAdress + "/Pictures/{0}.jpg", path);
  var client = new WebClient();
  client.OpenReadCompleted += ClientOpenReadCompleted1;
  client.OpenReadAsync(new Uri(outputString));
}

private static void ClientOpenReadCompleted1(object sender, OpenReadCompletedEventArgs e)
{
  var resInfo = new StreamResourceInfo(e.Result, null);
  var reader = new StreamReader(resInfo.Stream);

  byte[] contents;
  using (var bReader = new BinaryReader(reader.BaseStream))
  {
    contents = bReader.ReadBytes((int)reader.BaseStream.Length);
  }

  var file = IsolatedStorageFile.GetUserStoreForApplication();

  IsolatedStorageFileStream stream = file.CreateFile(PictureDataStoreLocal.ID.ToString());

  stream.Write(contents, 0, contents.Length);
  stream.Close();
}


I assume you want to process the pictures synchronously. If so I would use a wait handle. The easiest way to do this would be to declare a private AutoResetEvent field. The AutoResetEvent is good here because it just lets one thread through and then blocks again automatically.

If you do this you will need to make sure of two things: 1. You do ALL work on a different thread so that when you call WaitOne() you aren't blocking the thread that is supposed to be doing the work. 2. You always reset the wait handle regardless of the outcome of the server calls.

To take care of 1. you just need to update your loop:

m_waitHandle.Reset(); // Make sure the wait handle blocks when WaitOne() is called
for (int i = 0; i < amount; i++)
{
    // Process on a background thread
    ThreadPool.QueueUserWorkItem((obj) =>
    {
        // Get the current index. This is an anonymous method so if
        // we use 'i' directly we will not necessarily be using the
        // correct index. In our case the wait handle avoids this
        // problem as the pictures are downloaded one after the other
        // but it's still good practise to NEVER use a loop variable in
        // an anonymous method.
        int index = (int)obj;

        //to add picture to DB
        SavePicture(App.ViewModel.NewPictures[index]); 

        DownloadPicture(NewPictures[index].ID.ToString());
        DownloadPictureThumb(NewPictures[index].ID.ToString()));
    }, i);
    m_waitHandle.WaitOne(); // Wait for processing to finish
}

For 2. you need to make sure that m_waitHandle.Set() is ALWAYS called when processing is finished.