Reputation:
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
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