Scrolldown in ListView using ItemAppearing event skips records in Xamarin.Forms

4.6k Views Asked by At

I have ListView in Xamarin Page. I use ItemAppearing event to scroll down. ListViewCell height is big so 1 screen cover first and 80% part of second viewcell.

Steps to load more data for scroll down:

  1. Initially when page load, it call API and get 10 records in EmployerResult List. That will be added in ListView using databinding.
  2. Having ItemAppearing event. There is a condition in this event. When last cell start to appear, it will call API and again append 10 record in List object of ViewModel.
  3. So, this way it will call to API and append 10 record everytime when last cell start to appear.

Now the point is on every load, it skips last record and show first record of next 10 record. However sometimes it skips 2-3 records if user scrolldown fastly.

i.e if I have 10 records first time. Now I am on 9th record and I am scrolling down to 10. 10th record is starting to appear and API call fires. After this call completed, screen will show 11th record at top of the screen. Here, 10th record is skipped. This way user will see 11th record rather 10th. Here user need to scrollup again to see 10th record.

Sometimes, it skips 2-3 records if user scrolldown fastly.

Can anybody please suggest me?

Code

XAML

<ListView Grid.Row="0" x:Name="EmployerResultsListView"
          ItemsSource="{Binding EmployerResults}"
          HasUnevenRows = "true"
          SeparatorVisibility="None"
          IsPullToRefreshEnabled="true"
          RefreshCommand="{Binding RefreshCommand}"
          IsRefreshing="{Binding IsRefreshing, Mode=OneWay}"
          ItemAppearing="Handle_ItemAppearing"
          ItemTapped="OnEmployerResultsListViewItemTapped">
    <ListView.ItemTemplate>
        <DataTemplate>
            <local:EmployerResultViewCell />
        </DataTemplate>
    </ListView.ItemTemplate>
</ListView>

XAML.CS

private void Handle_ItemAppearing(object sender, ItemVisibilityEventArgs e)
{
    var itemTypeObject = e.Item as EmployerProfile;
    if (_viewModel.EmployerResults.Last() == itemTypeObject && _viewModel.EmployerResults.Count() != 1)
    {
        if (_viewModel.LoadMoreCommand.CanExecute(null))
        {
            _viewModel.LoadMoreCommand.Execute(null);
        }
    }
}

ViewModel

public EmployerResultsViewModel()
{
    LoadMoreCommand = new RelayCommand(LoadMoreEmployerResult, () => !IsBusy);
    EmployerResults = new ObservableRangeCollection<EmployerProfile>();
}
public ObservableRangeCollection<EmployerProfile> EmployerResults { get; set; }

private async void LoadMoreEmployerResult()
{
    IsBusy = true;
    EmployerResults.AddRange((await _employerApiClient.GetMoreData(pagenumber)));
    IsBusy = false;
}
2

There are 2 best solutions below

0
On BEST ANSWER

What I did is add additional blank cell at the end on LoadMoreEmployerResult and call for load more on appearing on that. On load more, I remove that blank cell. This is the only way I feel that can resolve my issue.

private async void LoadMoreEmployerResult()
{
    IsBusy = true;
    if(EmployerResults.Last().Name == "")
        EmployerResults.RemoveAt(EmployerResults.Count - 1);
    List<EmployerProfile> currentPageList= await _employerApiClient.GetMoreData(pagenumber);
    if(currentPageList.Count > 0)
    {
        EmployerResults.AddRange(currentPageList);
        EmployerResults.Add(new EmployerProfile());
    }

    IsBusy = false;
}
0
On

From my understanding, your are trying to do Lazy Loading.

-First, you should set the recycling Strategy like this: CachingStrategy="RecycleElement" if you want acceptable performances as described here https://learn.microsoft.com/en-us/xamarin/xamarin-forms/user-interface/listview/performance, then re-test the behavior of the ItemAppearing event.

-Then, it may be a good idea to use or to analyze an existing component that handles your need. For example: http://15mgm15.ghost.io/2017/11/28/implement-an-infinite-scrolling-listview-with-xamarin-forms/