Загрузка изображения из сети параллельным циклом ForEach - PullRequest
0 голосов
/ 21 февраля 2011

Привет, я хотел бы скачать изображения из сети в параллельном цикле foreach.

У меня есть словарь с подписью IDictionary<string,user>.Класс пользователя имеет два свойства:

Uri ProfilePhoto
BitmapImage ProfilePhotoAsBitmapImage

Моя цель - пройти словарь в цикле, если ProfilePhoto имеет нулевое значение. Я получаю аватар по умолчанию, но не хочу загружать изображение из Интернета асинхронно.

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

Проблема в том, что я не знаю, как извлечь объект BitmapImage из метода StartDownloading или метода ProcessImage, который находится внизу моего вопроса.

Запустить веб-запрос:

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

    //how retrieve result of ProcessImage 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 создается в методе ProcessImage. Как передать этот объект в свойство od Пользовательский объект, который используется в методе GetProfilePhotosFromServer?

Метод выше, созданный из объекта MemoryStream BitampImage.

1 Ответ

1 голос
/ 21 февраля 2011

Вам необходимо передать дополнительные операции и объект UserInfo в качестве обратного вызова асинхронного метода. Самый простой способ сделать это - создать класс, содержащий их, и передать его как асинхронное состояние метода.

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

}
...