Search code examples
c#windows-runtimewinrt-asyncwinrt-httpclient

Loading images with ISupportIncrementalLoading in WinRT app


I'm developing a Windows Phone 8.1 app and I would like use ISupportIncrementalLoading interface to load a list of objects from REST API server. Follow this article https://marcominerva.wordpress.com/2013/05/22/implementing-the-isupportincrementalloading-interface-in-a-window-store-app/ I created some classes where I'm downloading my objects in this way:

public class MyObject
{
   private ImageSource image;

   public int Id { get; set; }
   public string Desription { get; set; }
   public string PhotoLink { get; set; }
   public ImageSource Image
   {
       get
       {
           return this.image;
       }

       set
       {
           this.image = value;
           this.RaisePropertyChanged(() => this.Image);
       }
   }
}

And my source class to incremental loading data:

public async Task<IEnumerable<MyObject>> GetPagedItems(int pageIndex, int pageSize)
{
    var myObjects = await this.httpService.GetObjects(pageSize);
    if(myObjects != null)
    {
        foreach (var myObject in myObject)
        {       
            this.LoadImage(myObject);
        }
    }
    return myObjects;
}

private async void LoadImage(MyPbject myObject)
{
    if (myObject.PhotoLink != null)
    {
        var imageSource = await this.httpService.GetImage(myObject.PhotoLink);

        DispatcherHelper.CheckBeginInvokeOnUI(() =>
        {
            myObject.Image = imageSource;
        });
    }
}

Private object httpService is a class with methods to download data via HttpClient. For exapmle:

private async Task<ImageSource> GetImage(string imageUrl)
{
    using (HttpClient httpClient = new HttpClient())
    {
        using (Stream stream = await httpClient.GetStreamAsync(imageUrl))
        {
            using (MemoryStream memoryStream = new MemoryStream())
            {
                await stream.CopyToAsync(memoryStream);
                memoryStream.Position = 0;
                var bitmap = new BitmapImage();
                bitmap.SetSource(memoryStream.AsRandomAccessStream());
                return bitmap;
            }
        }
    }
}

I'm using a MVVMLight in my project and I've got a ViewModel with MyObjectsCollection (which implements ISupportIncrementalLoading of course) and I've got a standard ListView in a XAML with SourceItems binded to MyObjectsCollection. Everything works fine but only when I'am downloading MyObjects without photos. But when I'am using LoadImage method in foreach loop UI thread is locked and new objects occur after few seconds and user can't scroll or push buttons. What I'am doing wrong? Maybe I should assign Image to myObject.Image property in other way and not by Dispatcher? But how can I do that without COMException? Thanks for any help.


Solution

  • I think in this case you can binding the url to the source of the image, and use DecodePixelHeight and DecodePixelWidth to optimize the performance

    <Image>
        <Image.Source>
            <BitmapImage UriSource="{Binding ImageUrl}"
                                 DecodePixelHeight="200"
                                 DecodePixelWidth="200"
                                 DecodePixelType="Logical"/>
         </Image.Source>
    </Image>