I have a setup where the carouselview has a binded property "CurrentItem". When we set currentitem to the next page programatically the binded property will be set 4 times. 3 times the proper item, but 1 time it is the wrong (previous) object.
This has a negative effect on components that respond to the current page index like page button states or a stepsindicator.
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"
xmlns:d="http://xamarin.com/schemas/2014/forms/design"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
x:Class="TestCarousel.MainPage">
<StackLayout>
<StackLayout VerticalOptions="FillAndExpand" HorizontalOptions="FillAndExpand">
<CarouselView
x:Name="testCarousel"
ItemsSource="{Binding TestCollection}"
CurrentItem="{Binding CurrentTestModel}">
<CarouselView.ItemTemplate>
<DataTemplate>
<StackLayout>
<Label Text="Title"/>
<Label Text="{Binding Title}"/>
<Label Text="Description"/>
<Label Text="{Binding Description}"/>
</StackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<Button Text="Previous" Command="{Binding PreviousPageCommand}" />
<Button Text="Next" Command="{Binding NextPageCommand}" />
</StackLayout>
</StackLayout>
</ContentPage>
codebehind:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
using Xamarin.Forms;
namespace TestCarousel
{
// Learn more about making custom code visible in the Xamarin.Forms previewer
// by visiting https://aka.ms/xamarinforms-previewer
[DesignTimeVisible(false)]
public partial class MainPage : ContentPage, INotifyPropertyChanged
{
public MainPage()
{
InitializeComponent();
this.Appearing += MainPage_Appearing;
this.BindingContext = this;
this.testCarousel.Scrolled += TestCarousel_Scrolled;
this.testCarousel.CurrentItemChanged += TestCarousel_CurrentItemChanged;
}
private void MainPage_Appearing(object sender, EventArgs e)
{
this.TestCollection = new ObservableCollection<TestModel>()
{
new TestModel() { Title = "Title 1", Description = "Description 1"},
new TestModel() { Title = "Title 2", Description = "Description 2"},
new TestModel() { Title = "Title 3", Description = "Description 3"},
new TestModel() { Title = "Title 4", Description = "Description 4"},
new TestModel() { Title = "Title 5", Description = "Description 5"},
};
this.CurrentTestModel = TestCollection[0];
}
private ObservableCollection<TestModel> testCollection;
public ObservableCollection<TestModel> TestCollection
{
get
{
return testCollection;
}
set
{
testCollection = value;
RaisePropertyChanged();
}
}
private int pageIndex = 0;
public int PageIndex
{
get
{
return pageIndex;
}
set
{
pageIndex = value;
}
}
private TestModel currentTestModel;
public TestModel CurrentTestModel
{
get
{
return currentTestModel;
}
set
{
currentTestModel = value;
Debug.WriteLine($"CurrentPage changed to {TestCollection.IndexOf(value)}");
RaisePropertyChanged();
}
}
public Command NextPageCommand
{
get
{
return new Command(() => {
PageIndex++;
CurrentTestModel = TestCollection[PageIndex];
});
}
}
public Command PreviousPageCommand
{
get
{
return new Command(() => {
PageIndex--;
CurrentTestModel = TestCollection[PageIndex];
});
}
}
public event PropertyChangedEventHandler PropertyChanged;
/// <summary>
/// Raises the property changed.
/// </summary>
/// <param name="propertyName">(Optional) Property name.</param>
protected void RaisePropertyChanged([CallerMemberName] string propertyName = null)
{
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
}
}
public class TestModel
{
public string Title { get; set; }
public string Description { get; set; }
}
}
Steps to reproduce:
Unzip the sample project in the zipfile and run it.
CarouselView - Bugreport.zip
Tab the next button and you will see the following debugging line:

Results in the following debugging output:

System info:
Xamarin.Forms: 4.3.0.947036
Tested on: Android 8, Android 9
Update:
I have tested the same code in iOS (build against xcode 11) and it results in the same kind of problems.
When you tap on the next button, carousel does not animate to the next page. In XF 4.3.0.819712-pre2 it works perfectly fine but in the latest stable (4.3.0.947036) it is not working
Tested on iPhone 6 - iOS 12.4
I have a setup where the carouselview has a binded property "CurrentItem". When we set currentitem to the next page programatically the binded property will be set 4 times. 3 times the proper item, but 1 time it is the wrong (previous) object.
This has a negative effect on components that respond to the current page index like page button states or a stepsindicator.
Xaml:
codebehind:
Steps to reproduce:
Unzip the sample project in the zipfile and run it.
CarouselView - Bugreport.zip
Tab the next button and you will see the following debugging line:
Results in the following debugging output:
System info:
Xamarin.Forms: 4.3.0.947036
Tested on: Android 8, Android 9
Update:
I have tested the same code in iOS (build against xcode 11) and it results in the same kind of problems.
When you tap on the next button, carousel does not animate to the next page. In XF 4.3.0.819712-pre2 it works perfectly fine but in the latest stable (4.3.0.947036) it is not working
Tested on iPhone 6 - iOS 12.4