问题
While I was trying to implement an infinite scroll page I've encountered a strange behaviour with the CurrentItemChanged
event of Xamarin.Forms.CarouselView
.
While the user scrolls, new items are added to the ItemSource
and old items are removed (for low memory consumption).
After I encountered the strange behaviour I've debugged and narrowed down the problem.
So here are the steps to replicate the situation.
- Create a
CarouselView
. - Create a
ObservableCollection<T>
in the code behind and assign it to theItemSource
. - Create a method and subscribe it to the
CurrentItemChanged
event of theCarouselView
. This method must at some point remove an element from theItemSource
that has an index between0
and the index of theCurrentItem
. - Now deploy the app and swipe the
CarouselView
once. This will result in an endless loop of scrolls that will keep going untill all of the items are removed from theItemSource
.
The method from step 3 must look like below.
bool FirstTime = true;
private void StateChanged(object s, EventArgs e)
{
// Pass the first call which is made right after the Carousel is initialized.
if (FirstTime) { FirstTime = false; return; }
var currentItem = (Model)Carousel.CurrentItem; // For debug.
var index = Models.IndexOf(currentItem); // Same.
// Step 3's requirement
Models.RemoveAt(0);
}
When you instead for example add a button to the page and assign the method you've created at the step 3 to it's Clicked
event, and continue with the 4th step and manually press button after each scroll the endless loop won't occur.
I don't know if this is a feature or a bug but this certainly was unexpected, at least for me. I would love to figure out how to overcome this problem and learn why it works like this.
Note: I'm aware that removing the current item will cause such problem but the described behaviour occurs either ways. Also CarouselView.CurrentItem
is updated before the CurrentItemChanged
event is fired.
回答1:
This will result in an endless loop of scrolls that will keep going untill all of the items are removed from the ItemSource.
This is because ObservableCollection
has CollectionChanged event which will be called when the data collection is changed. When you remove the first item, the index is refershed and the event will also be triggered.
For this function, you could detect if the current item is the last one to update the data collection. Check the code:
public partial class Page1 : ContentPage
{
CustomViewModel viewModel = new CustomViewModel();
ObservableCollection<CustomModel> collection;
public Page1()
{
InitializeComponent();
BindingContext = viewModel;
collection = viewmodel.DataCollection;
}
private void CarouselView_CurrentItemChanged(object sender, CurrentItemChangedEventArgs e)
{
var item = e.CurrentItem as CustomModel;
var index = collection.IndexOf(item);
if (collection.Count == (index + 1))
{
collection.RemoveAt(0);
collection.Add(new CustomModel { ... });
}
}
}
来源:https://stackoverflow.com/questions/65106771/xamarin-bug-ish-behaviour-in-carouselview-currentitemchanged-event-fired-unexp