Reputation: 465
I am trying to create an infinite scroll in xamarin.forms. I think that the problem is, that my items are not binded to my ListView. Do I have to bind my datatemplate to listview. My datatemplate contains imagecell with text,detail and ImageSource.
While I was debugging, my listview.ItemAppearing += (sender, e) => was never called. So I am assuming that here is my problem.
I am using Http client with json response. Bellow is my code:
public partial class MainPage : ContentPage
{
readonly IList<Article> books = new ObservableCollection<Article>();
readonly BookManager manager = new BookManager();
bool isLoading;
public MainPage()
{
books = new ObservableCollection<Article>();
var listview = new ListView();
listview.ItemsSource = books;
listview.ItemAppearing += (sender, e) =>
{
if (isLoading || books.Count == 0)
return;
//hit bottom!
if (e.Item == books[books.Count - 1])
{
LoadItems();
}
};
LoadItems();
BindingContext = books;
InitializeComponent();
}
my LoadItems method:
public async void LoadItems()
{
//simulator delayed load
var bookCollection = await manager.GetAll();
foreach (Article book in bookCollection.articles)
{
books.Add(book);
}
}
and my xamlpage
<ContentPage xmlns="http://xamarin.com/schemas/2014/forms"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
x:Class="BookClient.MainPage"
Title="Library Books">
<ContentPage.ToolbarItems>
<ToolbarItem Text="Add New" Icon="ic_action_new.png" Clicked="OnAddNewBook" />
<ToolbarItem Text="Refresh" Icon="ic_autorenew.png" Clicked="OnRefresh" />
</ContentPage.ToolbarItems>
<ListView
ItemsSource="{Binding}"
ItemTapped="OnEditBook">
<ListView.ItemTemplate>
<DataTemplate>
<ImageCell
Text="{Binding id, StringFormat='ID= {0}'}" Detail="{Binding content}" ImageSource="{Binding images.image_intro}">
<ImageCell.ContextActions>
<MenuItem Clicked="OnDeleteBook"
CommandParameter="{Binding}"
Text="Delete" IsDestructive="True" />
</ImageCell.ContextActions>
</ImageCell>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
</ContentPage>
Upvotes: 1
Views: 3849
Reputation: 11105
Looks like you have a couple problems, though I have not messed with infinite scrolling before. To answer your question, you do not need to bind your DataTemplate
, it looks good exactly how you have it.
In your XAML you specify ItemsSource="{Binding}"
but then in your code-behind you set listview.ItemsSource = books;
which cancels out your original binding. I would suggest commenting out that line in your code-behind and leave in the XAML line.
You are not awaiting LoadItems();
. You should move LoadItems();
into OnAppearing()
so that it can be awaited.
Move the books
property into your ViewModel and then have you ViewModel inherit from INotifyPropertyChanged
and set your ViewModel as the BindingContext
. This would then make your ListView.ItemSource
change to ItemsSource="{Binding Books}"
. So your ViewModel will become
public class BooksViewModel : INotifyPropertyChanged {
public event System.ComponentModel.PropertyChangedEventHandler PropertyChanged;
private ObservableCollection<Article> _books;
public ObservableCollection<Article> Books {
get { return _books ?? (_books = new ObservableCollection<Article>()); }
set {
if(_books != value) {
_books = value;
OnPropertyChanged();
}
}
}
public async void LoadItems()
{
//simulator delayed load
var bookCollection = await manager.GetAll();
foreach (Article book in bookCollection.articles)
{
books.Add(book);
}
}
protected virtual void OnPropertyChanged([System.Runtime.CompilerServices.CallerMemberName] string propertyName = null) {
System.ComponentModel.PropertyChangedEventHandler handler = PropertyChanged;
if(handler != null) { handler(this, new System.ComponentModel.PropertyChangedEventArgs(propertyName)); }
}
}
Doing the above allows Books
to notify the UI that it has changed so the UI will update. You also should be specifying Books
as ObservableCollection<>
instead of IList<>
listview.ItemAppearing
in ContentPage.OnAppearing()
and then remove the event handler in ContentPage.OnDisappearing()
. This will prevent memory leaks and should be done for any event handling that it makes sense to do it to. This will require you to put your ItemAppearing
lambda code into its own methodLet me know if it is still not working for you after this.
Edit: Forgot about the ViewModel's PropertyChanged
event. See ViewModel code again, at the top.
Upvotes: 2