Search code examples
c#gridviewuwpimage-fileincremental-load

Displaying images in gridview using incremental loading


I have a gridview that displays 435 images on a local package. I tried using Incremental Loading.

XAML:

<GridView  
                            x:Name="komikGridView" Loaded="komikGridView_Loaded">
                                <GridView.Resources>
                                    <DataTemplate x:Key="DataTemplatekomikGridView">
                                        <Grid
                                        x:Name="komikGrid1">
                                            <Image
                                            x:Name="cover
                                            Width="160"
                                            Height="235"
                                            Source="{Binding Image}" />
                                        </Grid>
                                    </DataTemplate>
                                </GridView.Resources>
                                <GridView.ItemTemplate>
                                    <StaticResource ResourceKey="DataTemplatekomikGridView"/>
                                </GridView.ItemTemplate>
                            </GridView>

ItemsToShow Class:

public class ItemsToShow : ObservableCollection<string>, ISupportIncrementalLoading
    {
        public int lastItem = 1;

        public bool HasMoreItems
        {
            get
            {
                if (lastItem == 1000)
                {
                    return false;
                }
                else
                {
                    return true;
                }
            }
        }

        public IAsyncOperation<LoadMoreItemsResult> LoadMoreItemsAsync(uint count)
        {
            ProgressRing progressRing = ((Window.Current.Content as Frame).Content as LibraryPage).loading;
            CoreDispatcher coreDispatcher = Window.Current.Dispatcher;
            return Task.Run<LoadMoreItemsResult>(async () =>
            {
                await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,
                    () =>
                    {
                        progressRing.IsActive = true;
                        progressRing.Visibility = Visibility.Visible;
                    });

                //List<string> items = new List<string>();
                List<Book> items = new List<Book>();
                StorageFolder installedLocation = ApplicationData.Current.LocalFolder;
                StorageFolder _pdffolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
                _pdffolder = await _pdffolder.GetFolderAsync("files");
                _pdffolder = await _pdffolder.GetFolderAsync("pdf");
                _pdffolder = await _pdffolder.GetFolderAsync("komik");
                IReadOnlyList<StorageFile> _pdffiles = await _pdffolder.GetFilesAsync(); //which returns List<StorageFile>
                                                                                         //Debug.WriteLine("pdf: " + _pdffolder.Path);
                StorageFolder library = await installedLocation.CreateFolderAsync("library", CreationCollisionOption.OpenIfExists);
                StorageFolder komik = await library.CreateFolderAsync("komik", CreationCollisionOption.OpenIfExists);
                IReadOnlyList<StorageFile> files = await komik.GetFilesAsync();
                IEnumerable<Temp> sortingFiles = files.Select(x => new Temp { File = x }).ToList();
                foreach (var item in sortingFiles)
                {
                    //item.LastModified = (await item.File.GetBasicPropertiesAsync()).DateModified.DateTime;
                    item.Name = item.File.Name;
                }
                IEnumerable<StorageFile> sortedfiles = sortingFiles.OrderByDescending(x => x.LastModified).Select(x => x.File).ToList();
                StorageFolder _thumbfolder = Windows.ApplicationModel.Package.Current.InstalledLocation;
                _thumbfolder = await _thumbfolder.GetFolderAsync("files");
                _thumbfolder = await _thumbfolder.GetFolderAsync("cover");
                _thumbfolder = await _thumbfolder.GetFolderAsync("komik");
                IReadOnlyList<StorageFile> _coverfiles = await _thumbfolder.GetFilesAsync(); //which returns List<StorageFile>
                StorageFolder thumbfolder = await installedLocation.CreateFolderAsync("thumb", CreationCollisionOption.OpenIfExists);
                StorageFolder komikthumb = await thumbfolder.CreateFolderAsync("komik", CreationCollisionOption.OpenIfExists);
                IReadOnlyList<StorageFile> thumbfiles = await komikthumb.GetFilesAsync();
                string filePath = "";
                foreach (StorageFile file in sortedfiles)
                {
                    Book book = new Book();
                    //FileItem book = new FileItem();
                    book.Name = file.DisplayName.ToString();
                    Debug.WriteLine("judul: " + book.Name);
                    StorageFile thumbFile = await komikthumb.GetFileAsync(file.Name.ToString() + ".png");
                    string path = komikthumb.Path;
                    filePath = Path.Combine(path, file.Name.ToString() + ".png");
                    BitmapImage bi = new BitmapImage();
                    bi.SetSource(await thumbFile.OpenAsync(FileAccessMode.Read));
                    book.Image = bi;
                    for (int i = 0; i < count; i++)
                    {
                        var p = new Book { Name = book.Name, Image = book.Image };
                        items.Add(p);
                        lastItem++;
                        if (lastItem == items.Count)
                        {
                            break;
                        }
                    }
                    Debug.WriteLine("jumlah: " + items.Count);
                }
                await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,
                    () =>
                    {
                        foreach (Book item in items)
                        {
                            //this.Add(item);
                            string _b64 = Convert.ToBase64String(File.ReadAllBytes(item.Path));
                            this.Add(_b64);
                        }
                        progressRing.Visibility = Visibility.Collapsed;
                        progressRing.IsActive = false;
                    });
                return new LoadMoreItemsResult() { Count = count };
            }).AsAsyncOperation<LoadMoreItemsResult>();
        }

        public class Temp
        {
            public StorageFile File { get; set; }
            public DateTime LastModified { get; set; }
            public string Name { get; set; }
        }
    }

Code:

private void komikGridView_Loaded(object sender, RoutedEventArgs e)
    {
        komikGridView.ItemsSource = new ItemsToShow();
    }

But I'm having a problem, i.e. the image doesn't display successfully on the gridview. How to handle it? And how to display 16 images first and when scrolled will display the next 16 images and so on?


Solution

  • Displaying images in gridview using incremental loading

    I found you refer this case reply, but for this scenario, you need to replace ObservableCollection<string> with ObservableCollection<Book>, because you have bind Image control with Book Image property.

     <Image x:Name="cover"  Width="160"  Height="235" Source="{Binding Image}" />
    

    And the secondly you need to call Add metod to add Book instance but not base64 string. because image control can't render base64 directly.

    await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,
    () =>
    {
        foreach (Book item in items)
        {
            this.Add(item);
        }    
    });
    

    When you finished above, you could set break point in this.Add(item); line to check if it has avaiable item.

    Update

    Please try to call LoadMoreItemsAsync manually like the following.

    private async void KomikContent()
     {
         var items = new ItemsToShow();
         komikGridView.ItemsSource = items;
         await items.LoadMoreItemsAsync(10);
     }
    

    update 1

    public class Book
    {
    
        public string Name { get; set; }
        public string Image { get; set; }
    }
    
    
    await coreDispatcher.RunAsync(CoreDispatcherPriority.Normal,
    async () =>
      {
    
          book.Image = thumbFile.Path;
          Add(book);
      });
    

    update 2

    And if you want to make mutiple pages for gridview, this document is best practice, you can refer it to make your own BookSource class and initialize data in it.

    private void MainPage_Loaded(object sender, RoutedEventArgs e)
    {
        var booksource = new BookSource();
        collection = new IncrementalLoadingCollection<BookSource,Book>(booksource, 35);
        komikGridView.ItemsSource = collection;
       
    }