Quantcast
Channel: Xamarin.Forms — Xamarin Community Forums
Viewing all articles
Browse latest Browse all 91519

Issues with adding ListView items in ItemAppearing

$
0
0

I'm trying to get a ListView to display with infinite scrolling, similar to Rob Gibbens' solution. However, I'm running into a few issues that seem to occur when I try to load additional data in the ItemAppearing event on the list view. I've only run the project on iOS, so I am unsure it the issues happen on Android or WP as well.

  • When the user quickly scrolls past the current end of the list, the application crashes, and the debugger catches the following exception:

    MonoTouch.Foundation.MonoTouchException: Objective-C exception thrown. Name: NSRangeException Reason: *** -[__NSArrayM objectAtIndex:]: index 8 beyond bounds [0 .. 7]

    I'm guessing that this has to do with trying to display new items as they are still loading as it only happens when the end is quickly scrolled past, but I'm not sure if this is a bug or just something that I don't know how to handle gracefully.

  • Scrolling down causes no issues, but when the user scrolls up, sometimes the bottom item disappears preemptively and the cell remains empty until it is removed and re-added by the ItemDisappearing and ItemAppearing calls, respectively. I'm not sure what is causing the cell to disappear, as it seems to happen fairly randomly (the same cells don't always disappear) and I cannot find an event that is triggered as it disappears.

  • If I select items that were populated through the ItemAppearing event, a different item is highlighted (e.g. I select item 20, but item 19 is highlighted)

All of these issues only happen when I load data through the ItemAppearing event (which seems to be the way I'm supposed to do that going from the post by @ermau), so my question is: Are these caused because I'm not doing something that I'm supposed to be doing in the event handler, or are they bugs?

I've attached 3 images that should help explain the second issue (a picture is worth a thousand words), and the code for the page is as follows:

XAML:

<?xml version="1.0" encoding="UTF-8"?>
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms" xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml" x:Class="InfiniteScrolling.MainPage">
    <ContentPage.Padding>
        <OnPlatform x:TypeArguments="Thickness" iOS="5,20,5,5" Android="5,0,5,5" WinPhone="5,0,5,5" />
    </ContentPage.Padding>
    <StackLayout>
        <Button x:Name="loadData" Text="Load" HorizontalOptions="FillAndExpand" />
        <ListView x:Name="mainList" VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand" ItemsSource="{Binding Items}" />
    </StackLayout>
</ContentPage>

Code Behind:

using System.Linq;
using System.Threading.Tasks;
using Xamarin.Forms;

namespace InfiniteScrolling
{
    public partial class MainPage : ContentPage
    {
        readonly MainViewModel _viewModel;
        int _start = 0;
        const int _numberOfRecords = 15;

        public MainPage ()
        {
            InitializeComponent ();
            _viewModel = new MainViewModel ();
            this.BindingContext = _viewModel;
            this.loadData.Clicked += async (sender, e) => {
                await LoadData ();
            };

            this.mainList.ItemAppearing += OnItemAppearing;
        }

        async void OnItemAppearing(object Sender, ItemVisibilityEventArgs e)
        {
            var item = (int)e.Item;
            if (!_viewModel.IsLoading && item == _viewModel.Items.Last())
                await LoadData();
        }

        async Task LoadData ()
        {
            await _viewModel.LoadData (_start, _numberOfRecords);
            _start = _start + _numberOfRecords;
        }
    }
}

Viewmodel:

using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Threading.Tasks;

namespace InfiniteScrolling
{
    public class MainViewModel : INotifyPropertyChanged
    {
        public event PropertyChangedEventHandler PropertyChanged;

        public MainViewModel ()
        {
        }

        ObservableCollection<int> _items;
        public ObservableCollection<int> Items {
            get {
                if (_items == null)
                    _items = new ObservableCollection<int> ();

                return _items;
            }
            set {
                _items = value;
                PropertyChanged (this, new PropertyChangedEventArgs ("Items"));
            }
        }

        bool isLoading;
        public bool IsLoading {
            get {
                return isLoading;
            }
            set {
                if (isLoading != value) {
                    isLoading = value;
                    PropertyChanged (this, new PropertyChangedEventArgs ("IsLoading"));
                }
            }
        }

        public async Task LoadData (int start, int numberOfRecords)
        {
            this.IsLoading = true;
            for (int counter = 0; counter < numberOfRecords; counter++)
                Items.Add (start + counter);

            this.IsLoading = false;
        }
    }
}

Thanks!


Viewing all articles
Browse latest Browse all 91519

Trending Articles



<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>