user572844
user572844

Reputation:

Downloading image from web asychrounly in parallel ForEach loop

Hi I would like download images from web asychrounly in parallel loop foreach.

I have dictionary with signature IDictionary<string,user>. User class has two properties:

Uri ProfilePhoto
BitmapImage ProfilePhotoAsBitmapImage

My aim is, go through dictionary in loop if ProfilePhoto is null I get default avatar, it not I would like download image from web asynchronly.

    private void GetProfilePhotosFromServer(IEnumerable<UserInfo> friends)
    {
        Parallel.ForEach(friends, f =>
        {
            //get defualt
            if (f.ProfilePhoto == null) 
                f.ProfilePhotoAsBitmap = CreateDefaultAvatar(f.Sex);

            //start downloading from web server asynchronly
            //problem is that I don’t know how retrieve BitmapImage object from 
            //StartDownloading method or method ProcessImage, which is on the bottom
            //of my question
            var image = StartDownloadingImage(f.MediumProfilePhoto);
            image.Freeze();

            f.ProfilePhotoAsBitmap = image;
        });
    }

Problem is that I don’t know how retrieve BitmapImage object from StartDownloading method or method ProcessImage, which is on the bottom of my question.

Start web request:

private void StartDownloadingImage(Uri imageUri)
{
    _webRequest = WebRequest.Create(imageUri);
    _webRequest.BeginGetResponse(this.ProcessImage, null);

    //how retrieve result of ProcessImage method
}

After web request is finished I call this method:

    private void ProcessImage(IAsyncResult asyncResult)
    {
        var response = _webRequest.EndGetResponse(asyncResult);

        using (var stream = response.GetResponseStream())
        {
            var buffer = new Byte[response.ContentLength];
            int offset = 0, actuallyRead = 0;
            do
            {
                actuallyRead = stream.Read(buffer, offset, buffer.Length - offset);
                offset += actuallyRead;
            }
            while (actuallyRead > 0);


            var image = new BitmapImage
            {
                CreateOptions = BitmapCreateOptions.None,
                CacheOption = BitmapCacheOption.OnLoad
            };
            image.BeginInit();

            image.StreamSource = new MemoryStream(buffer);

            image.EndInit();

            //problem
            return image;
        }

    }

BitmapImage object is created in ProcessImage method how can I pass this object to the property od User object which is used in GetProfilePhotosFromServer method?

Method above create from MemoryStream BitampImage object.

Upvotes: 0

Views: 1897

Answers (1)

tvanfosson
tvanfosson

Reputation: 532695

You need to pass in the additional operations and the UserInfo object as a callback to the asynchronous method. The easiest way to do this is to create a class containing them and pass that as the asynchronous state of the method.

private class ImageCallbackState
{
     public UserInfo Friend { get; set; }
     public Action<UserInfo,BitmapImage> Callback { get; set; }
}

private void GetProfilePhotosFromServer(IEnumerable<UserInfo> friends)
{
    Parallel.ForEach(friends, f =>
    {
        //get defualt
        if (f.ProfilePhoto == null) 
            f.ProfilePhotoAsBitmap = CreateDefaultAvatar(f.Sex);

        Action<UserInfo,BitmapImage> action = (u,i) => {
              i.Freeze();
              u.ProfilePhotoAsBitMap = i;
        };
        var state = new ImageCallbackState { Friend = f, Callback = action };
        StartDownloadingImage(f.MediumProfilePhoto,state);

    });
}

private void StartDownloadingImage(Uri imageUri, ImageCallbackState state)
{
    _webRequest = WebRequest.Create(imageUri);
    _webRequest.BeginGetResponse(this.ProcessImage, state); // pass callback state
}

private void ProcessImage(IAsyncResult asyncResult)
{
    var response = _webRequest.EndGetResponse(asyncResult);

    using (var stream = response.GetResponseStream())
    {
        var buffer = new Byte[response.ContentLength];
        int offset = 0, actuallyRead = 0;
        do
        {
            actuallyRead = stream.Read(buffer, offset, buffer.Length - offset);
            offset += actuallyRead;
        }
        while (actuallyRead > 0);


        var image = new BitmapImage
        {
            CreateOptions = BitmapCreateOptions.None,
            CacheOption = BitmapCacheOption.OnLoad
        };
        image.BeginInit();

        image.StreamSource = new MemoryStream(buffer);

        image.EndInit();

        var state = asyncResult.AsyncState as ImageCallbackState

        state.Callback(state.Friend,image);
    }

}

Upvotes: 1

Related Questions