Forum Xamarin Xamarin.Forms

Load Async Images in ListView

DimChrisDimChris USMember ✭✭✭✭

Hello developers, i am using FFImageLoading. I need to populate a listview with large images. Which is the best method?

Should i set url in source? Or it is better to handle it in Listview's itemappearing event?

`private void ListviewItems_ItemAppearing(object sender, ItemVisibilityEventArgs e)
{

        var item = e.Item as InventoryItemsClass;
        if (item != null)
        {
            //Here i maje my Get Request
        }
    }`

Best Answer

Answers

  • jezhjezh Member, Xamarin Team Xamurai
    edited September 16

    Since nuget Xamarin.FFImageLoading does some work with disk and image caching, you can just bind image's url in source.

    And there is a sample in link: https://github.com/luberda-molinet/FFImageLoading, you can refer to it.

    For example:

            <ListView CachingStrategy="RecycleElement" HasUnevenRows="false"
                    RowHeight="180" SelectedItem="{Binding SelectedItem, Mode=TwoWay}" ItemsSource="{Binding Items}">
    
                <ListView.Behaviors>
                    <xamvvm:BaseEventToCommandBehavior EventName="ItemSelected" Command="{Binding ItemSelectedCommand}"/>
                </ListView.Behaviors>
    
                <ListView.ItemTemplate>
                    <DataTemplate>
                        <local:CustomKeyPageCell/>
                    </DataTemplate>
                </ListView.ItemTemplate>
    
            </ListView>
    

    Besides, you can also check official document Improve Xamarin.Forms App Performance.

    Please pay attention to Optimize ListView performance and Optimize image resources.

  • DimChrisDimChris USMember ✭✭✭✭

    Thank you Jezh. Here is my example but unfortunately it doesnt work.

    <ListView.ItemTemplate>
                        <DataTemplate>
                            <ViewCell>
    
    
                                <StackLayout Margin="10,10,10,10" Spacing="0">
                                    <ff:CachedImage
                                           Source="{Binding ImageUrl}"
                                           FadeAnimationEnabled="False"
                                           FadeAnimationDuration="0"
                                           LoadingDelay="0"
                                           DownsampleToViewSize="True"
                                           IsVisible="{Binding ImageVisibility}"
                                           HeightRequest="{Binding ImageDynamicHeight}"
                                           Aspect="Fill"/>
                                </StackLayout>
    
                          </ViewCell>
                        </DataTemplate>
                    </ListView.ItemTemplate>
    

    Also in server Side

    [Route("api/InventoryItemImage/{inventoryItemID}/{databaseName}")]
            public HttpResponseMessage Get(int inventoryItemID, string databaseName)
            {
                var dbHelper = new DatabaseHelper();
                using (var connection = new SqlConnection(dbHelper.CustomConnectionString(databaseName)))
                {
                    connection.Open();
                    using (var cmd = new SqlCommand("Select top(1) ItemImage from InventoryMaster where InventoryItemID=" + inventoryItemID + "", connection))
                    using (var read = cmd.ExecuteReader())
                    {
                        while (read.Read())
                        {
                            var response = new HttpResponseMessage();
                            var byteArray = (byte[])read["ItemImage"];
                            response.Content = new ByteArrayContent(byteArray);
                            response.Content.LoadIntoBufferAsync(byteArray.Length).Wait();
                            response.Content.Headers.ContentType = new MediaTypeHeaderValue("image/jpeg");
                            return response;
                        }
    
                    }
                    return null;
                }
            }
    

    And Here is my class

    public class InventoryItemsClass : INotifyPropertyChanged
    {
    public event PropertyChangedEventHandler PropertyChanged;

        private string _imageUrl= null;
    
        public string ImageUrl
        {
            get { return _imageUrl; }
            set
            {
                if (_name == value)
                    return;
                _imageUrl= value;
                OnPropertyChanged();
            }
        }
    
        private void OnPropertyChanged([CallerMemberName] string propertyName = null)
        {
            PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
    }
    
  • jezhjezh Member, Xamarin Team Xamurai

    Here is my example but unfortunately it doesnt work.

    What are the specific problem?How did your app not work ?

    Could you please post relative error log about this question?

  • DimChrisDimChris USMember ✭✭✭✭

    Jezh i found my solution. I replaced this inside get method

      ```
    

    byte[] imgData = img.ImageData;

      MemoryStream ms = new MemoryStream(imgData);
    
      HttpResponseMessage response = new HttpResponseMessage(HttpStatusCode.OK);
    
      response.Content = new StreamContent(ms);
    
      response.Content.Headers.ContentType = new 
      System.Net.Http.Headers.MediaTypeHeaderValue("image/png");
       //send response of image/png type
      return response;
    

    ```

    One last question is there any way to get image from binding source?
    Example :smile:

    var image= MainImage.Source;

Sign In or Register to comment.