Varias llamadas a métodos asíncronos en un bucle Window Phone 7

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 métodos.

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;
}

Segundo;

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();
}

preguntado el 08 de noviembre de 11 a las 14:11

3 Respuestas

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.

respondido 09 nov., 11:12

Thanks for your answer, but it is not help. The method is still downloading and save only last picture, any suggestion - infoexpert.it

What does PictureDataStoreLocal.ID.ToString() return. You are using this as the filename but it doesn't appear to be dependent on the current picture. I have also edited my post to avoid a problem with the 'i' variable in the loop. - calma

public void DownloadPictureThumb(string path) string path = PictureDataStoreLocal.ID.ToString(); it is integer to string. I have made object Picture PictureDataStoreLocal for the Class - infoexpert.it

But that means that the following line will always overwrite the previous file (the filename will never change): IsolatedStorageFileStream stream = file.CreateFile(PictureDataStoreLocal.ID.ToString()); - calma

No, I have change code little for this question. In my code SavePicture(Picture picture); and than PictureDataStoreLocal = picture; where PictureDataStoreLocal global one. As I sad, no problem with this method.The problem with two asynchronous methods in the loop. Some how I need to make them work. - infoexpert.it

What I do is send extra parameters to the OpenReadCompleted event using a delegate like so,

someimage.LoadingCompleted += delegate(object sender, EventArgs imge) { someimage_LoadingCompleted(sender, imge, _item, "someimage"); };

and then in someimage_LoadingCompleted I have code within a switch statement.

respondido 08 nov., 11:18

Here is my solution, not that elegant but working one; If you have any suggestion to improve , please post and I will edit my post.

    EventWaitHandle m_WaitHandle;

    public bool AddAllPhoto()
    {
      var amount = App.ViewModel.NewPictures.Count;
    if (m_WaitHandle!=null)
                m_WaitHandle.Reset();
      for (int i = 0; i < amount; i++)
      {
    {
                    SavePicture(App.ViewModel.NewPictures[i]);
                    ThreadPool.QueueUserWorkItem((obj) =>
        {
            var index = (int)obj;
            DownloadPictureThumb(App.ViewModel.NewPictures[index].ID.ToString());
            DownloadPicture(App.ViewModel.NewPictures[index].ID.ToString());

        },i);
              if (m_WaitHandle != null) m_WaitHandle.WaitOne();
                }

                return true;
            }

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

            private static void ClientOpenReadCompleted2(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}", e.UserState as string);

                var stream = file.CreateFile(thumbFilePath);

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

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), path);
            }

            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 stream = file.CreateFile(e.UserState as string);


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

[Here][1] you will find explanation to how to get the url from WebClient in OpenReadCompleted?

respondido 10 nov., 11:13

No es la respuesta que estás buscando? Examinar otras preguntas etiquetadas or haz tu propia pregunta.