Search code examples
c#xamarinxamarin.formsxamarin.android

Loading data incrementally in Collection view


I am trying to load data incrementally but the RemainingItemsThresholdReachedCommand is not triggered by RemainingItemsThreshold Here the doc related to this : https://learn.microsoft.com/fr-fr/xamarin/xamarin-forms/user-interface/collectionview/populate-data :

here my collection view page :

<ContentPage.Content>
    <StackLayout BackgroundColor="#b4b4b4">
        <RefreshView Command="{Binding RefreshItemsCommand}" IsRefreshing="{Binding IsRefreshing}" >
            <CollectionView x:Name="CollectionViewThumbnails" SelectionMode="Multiple" Margin="13" ItemsSource="{Binding Items}" 
                              RemainingItemsThresholdReachedCommand="{Binding ItemTresholdReachedCommand}"
                              RemainingItemsThreshold="{Binding ItemTreshold}">
                <CollectionView.ItemsLayout>
                    <GridItemsLayout Orientation="Vertical" Span="1" VerticalItemSpacing="13" HorizontalItemSpacing="13"/>
                </CollectionView.ItemsLayout>
                <CollectionView.ItemTemplate>
                    <DataTemplate x:Name="data">
                        <Frame >
                            <StackLayout>
                                <Image Source="{Binding EmplacementThumbnails}" Aspect="AspectFill"/>
                            </StackLayout>
                        </Frame>
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </RefreshView>
        <ActivityIndicator IsRunning="{Binding IsBusy}"
                       HeightRequest="30"
                       HorizontalOptions="Center"
                       VerticalOptions="Center"
                       WidthRequest="30"/>
        <StackLayout>
            <Button Text="Go" Clicked="StartProcessConcatePages"/>
        </StackLayout>
    </StackLayout>
</ContentPage.Content>

My code behind :

 public partial class ConcatePageThumbnails : ContentPage
{
    FileEndpoint fileEndpoint = new FileEndpoint();
    FileInfo fileInfo;
    BitmapDataStore viewModel;

    protected async override void OnAppearing()
    {
        base.OnAppearing();

        if (viewModel.Items.Count == 0)
            viewModel.LoadItemsCommand.Execute(null);

        MessagingCenter.Subscribe<object, ThumbnailsModel>(this, BitmapDataStore.ScrollToPreviousLastItem, (sender, item) =>
        {
            CollectionViewThumbnails.ScrollTo(item, ScrollToPosition.End);
        });
    }

//TODO -- Gerer le retour 
public ConcatePageThumbnails(FileInfo fileInfo)
    {
        InitializeComponent();

        this.fileInfo = fileInfo;
        BindingContext = viewModel = new BitmapDataStore(fileInfo);

    }

}

And my view model :

public class BitmapDataStore
{
    IGetThumbnails getThumbnails;
    FileInfo fileInfo;
    public List<ThumbnailsModel> Items { get; set; }
    public Command LoadItemsCommand { get; set; }
    public Command ItemTresholdReachedCommand { get; set; }
    public Command RefreshItemsCommand { get; set; }
    public const string ScrollToPreviousLastItem = "Scroll_ToPrevious";
    private int _itemTreshold;
    private bool _isRefreshing;
    bool isBusy = false;
    public bool IsBusy
    {
        get { return isBusy; }
        set { isBusy = value; }
    }
    public bool IsRefreshing
    {
        get { return _isRefreshing; }
        set { _isRefreshing = value; }
    }

    public int ItemTreshold
    {
        get { return _itemTreshold; }
        set { _itemTreshold = value; }
    }

    public BitmapDataStore(FileInfo fileInfo)
    {
        ItemTreshold = 2;
        Items = new List<ThumbnailsModel>();
        this.fileInfo = fileInfo;
        getThumbnails = DependencyService.Get<IGetThumbnails>();

        LoadItemsCommand = new Command(async () => await ExecuteLoadItemsCommand());
        ItemTresholdReachedCommand = new Command(async () => await ItemsTresholdReached());
        RefreshItemsCommand = new Command(async () =>
        {
            await ExecuteLoadItemsCommand();
            IsRefreshing = false;
        });
    }

    async Task ItemsTresholdReached()
    {
        if (IsBusy)
            return;

        IsBusy = true;

        try
        {
            var items = await getThumbnails.GetBitmaps(fileInfo.FullName, Items.Count);

            var previousLastItem = Items.Last();
            foreach (var item in items)
            {
                Items.Add(item);
            }
            Debug.WriteLine($"{items.Count()} {Items.Count} ");
            if (items.Count() == 0)
            {
                ItemTreshold = -1;
                return;
            }
            MessagingCenter.Send<object, ThumbnailsModel>(this, ScrollToPreviousLastItem, previousLastItem);
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
        finally
        {
            IsBusy = false;
        }
    }

    async Task ExecuteLoadItemsCommand()
    {
        if (IsBusy)
            return;

        IsBusy = true;

        try
        {
            ItemTreshold = 2;
            Items.Clear();
            var items = await getThumbnails.GetBitmaps(fileInfo.FullName, Items.Count);
            foreach (var item in items)
            {
                Items.Add(item);
            }
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex);
        }
        finally
        {
            IsBusy = false;
        }
    }
}

My Dependencyservice class where I get the thumbnails and The items for my Collection view :

 public async Task<List<ThumbnailsModel>> GetBitmaps(string filePath, int lastIndex = 0)
    {
        var sw = new Stopwatch();
        sw.Start();

        int numberOfItemsPerPage = 6;
        PdfRenderer pdfRenderer = new PdfRenderer(GetSeekableFileDescriptor(filePath));

        var appDirectory = System.Environment.GetFolderPath(System.Environment.SpecialFolder.MyDocuments);
        string fileName = System.IO.Path.GetFileNameWithoutExtension(filePath);
        string directoryPath = System.IO.Path.Combine(appDirectory, "thumbnailsTemp", System.IO.Path.GetFileNameWithoutExtension(fileName));
        List<ThumbnailsModel> thumbnailsModels = new List<ThumbnailsModel>();

        if (!Directory.Exists(directoryPath))
        {
            Directory.CreateDirectory(directoryPath);
        }
            //int pageCount = pdfRenderer.PageCount;

            for (int i = lastIndex; i < lastIndex + numberOfItemsPerPage; i++)
            {
                PdfRenderer.Page page = pdfRenderer.OpenPage(i);
                Android.Graphics.Bitmap bmp = Android.Graphics.Bitmap.CreateBitmap(page.Width, page.Height, Android.Graphics.Bitmap.Config.Argb4444);
                page.Render(bmp, null, null, PdfRenderMode.ForDisplay);

                try
                {
                    using (FileStream output = new FileStream(System.IO.Path.Combine(directoryPath, fileName + "Thumbnails" + i + ".png"), FileMode.Create))
                    {
                        bmp.Compress(Android.Graphics.Bitmap.CompressFormat.Png, 0, output);
                    }

                    page.Close();
                }
                catch (Exception ex)
                {
                    //TODO -- GERER CETTE EXPEXPTION
                    throw new Exception();
                }
            }



        int y = 1;
        Directory.GetFiles(directoryPath).ToList<string>().Skip(lastIndex).Take(numberOfItemsPerPage).ForEach(delegate (string thumbnailsEmplacement)
        {
            thumbnailsModels.Add(new ThumbnailsModel(y, thumbnailsEmplacement));
            y++;
        });

        sw.Stop();





        return await Task.FromResult(thumbnailsModels);
    }

I tried to change the ItemTreshold value but doesn't work... Any idea ?

Update :

With different test I saw that ItemTreshold and RemainingItemsThresholdReachedCommand are triggered but not as expected.

My collection view is loading with the number of item set but When I am going down and I am triggering RemainingItemsThresholdReachedCommand this method is triggered consecutively

For example I have 30 Pages : the first 6 pages are loading but when RemainingItemsThresholdReachedCommand is triggered for the first time, and again and again until all the pages and items are done. Then nothing happen on the ui collection view screen.


Solution

  • I just started from sratch with this sample and now it work : https://forums.xamarin.com/discussion/comment/402926#Comment_402926