Search code examples
c#listviewdata-bindingxamarin.formslistviewitem

Xamarin Forms - Binding Listview for lazy loading


Started to dabble in Xamarin Forms. Two things I cant figure out:

Binding of my Listview:

I have a class with:

    public class Mainlist
    {
        public string Title
        {
            get;
            set;
        }
        public string Value
        {
            get;
            set;
        }

    }

My XAML looks like:

   <ListView x:Name="mainlist">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <StackLayout Orientation="Horizontal">
                            <StackLayout Orientation="Vertical">
                                <Label Text="{Binding Title}" Font="18"></Label>
                                <Label Text="{Binding Value}" TextColor="Gray"></Label>
                            </StackLayout>
                        </StackLayout>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

What happens now is that i have a list of URLS. From every URL I am scraping certain info with HTMLAgilityPack foreach loop, which is working fine.

I would like to add the scraped data after each run of the loop to the listview and have it display. Something like "lazy loading".

Up to now i could only figure out how to set the itemsource after all Urls are scraped and have it display at once with something like this:

 //set itemsource to URL collection
            mainlist.ItemsSource = new List<Mainlist>() {
                new Mainlist()
            {

              //scraped info from each URL
                    Title = title.ToString().Trim(),
                    Value = value.ToString().Trim(),

                },
            };

Solution

  • First, create a view model class, called MyViewModel.cs:

    public class MyViewModel : INotifyPropertyChanged
    {
        // property changed event handler
        public event PropertyChangedEventHandler PropertyChanged;
    
        private ObservableCollection<Mainlist> _list;
    
        public ObservableCollection<Mainlist> List
        {
            get { return _list; }
            set
            {
                _list = value;
                PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(nameof(List)));
            }
        }
    
        public MyViewModel()
        {
            _list = new ObservableCollection<Mainlist>();
        }
    
        public async void StartScraping()
        {
            // assuming you are 'awaiting' the results of your scraping method...
            foreach (...)
            {
                await ... scrape a web page ...
    
                var newItem = new Mainlist()
                {
                    Title = title.ToString().Trim(),
                    Value = value.ToString().Trim()
                };
    
                // if you instead have multiple items to add at this point,
                // then just create a new List<Mainlist>, add your items to it,
                // then add that list to the ObservableCollection List.
    
                Device.BeginInvokeOnMainThread(() => 
                {
                    List.Add(newItem);
                });
            }
    
        }
    }
    

    Now in your page's xaml.cs code behind file, set the view model as your BindingContext:

    public class MyPage : ContentPage // (assuming the page is called "MyPage" and is of type ContentPage)
    {
        MyViewModel _viewModel;
    
        public MyPage()
        {
            InitializeComponent();
            _viewModel = new MyViewModel();
            BindingContext = _viewModel;
            // bind the view model's List property to the list view's ItemsSource:
            mainList.setBinding(ListView.ItemsSourceProperty, "List");
        }
    }
    

    And note that in your view model, you'll need to use an ObservableCollection<T> instead of a List<T>, as ObservableCollection<T> will allow the ListView to be updated automatically whenever you add or remove items from it.

    Also, to ease a bit of confusion, I'd recommend changing the class name from Mainlist to MainListItem.