0

안녕하세요, 병렬 루프 foreach에서 웹 asychrounly에서 이미지를 다운로드하고 싶습니다.웹에서 asycrounly 병렬로 이미지 다운로드 ForEach 루프

나는 IDictionary<string,user>이라는 서명이있는 사전이 있습니다. 사용자 클래스는 두 가지 속성이 있습니다 ProfilePhoto 내가 기본 아바타를 얻을 null의 경우

Uri ProfilePhoto 
BitmapImage ProfilePhotoAsBitmapImage 

내 목표는, 루프에서 사전 통과되어, 그것은 내가 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; 
     }); 
    } 

문제는 내 질문의 하단에 StartDownloading 방법 또는 방법 ProcessImage에서 BitmapImage 개체를 검색하는 방법을 모르는 것입니다.

시작 웹 요청 : BitmapImage 개체 ProcessImage 방법에 생성됩니다

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

    } 

이 어떻게 속성 OD 사용이 개체를 전달할 수 있습니다 웹 요청 내가이 메소드를 호출 완료

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

    //how retrieve result of ProcessImage method 
} 

후 GetProfilePhotosFromServer 메서드에서 사용되는 개체?

위 메서드는 MemoryStream BitampImage 개체에서 만듭니다.

답변

1

추가 작업과 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); 
    } 

} 
+0

빠른 피드백에 감사드립니다. 나는 조금 혼란스러워합니다. 내 시나리오는 WPF 응용 프로그램의 UI 컨트롤에 ProfilePhotoAsBitamp 속성을 바인딩한다는 것입니다. app을 실행하면 오류가 발생하며 DependencyObject와 동일한 스레드에서 DependencySource를 작성해야합니다. 프로퍼티 ProfilePhotoAsBitmap의 객체가 UI 쓰레드로 다른 쓰레드에서 생성된다고 가정하지만, 여러분과 저는 또한이 객체에 대해 ProcessImage 메소드와 GetProfilePhotosFromServer에서 Freeze 메소드를 호출합니다. –

+0

@ 존 - 저는 WPF를 사용하지 않기 때문에 많은 도움이되지 않을 것 같습니다. – tvanfosson

+0

괜찮습니다. 답변을 표시합니다. –