From 28b9aa2be6df1e34adec6947d0b17b4a1f137063 Mon Sep 17 00:00:00 2001
From: Rui Marinho <me@ruimarinho.net>
Date: Mon, 25 Jan 2021 20:02:06 +0000
Subject: [PATCH 1/3] [Controls] Add test sample for #13296

---
 .../CarouselXamlGallery.xaml                  |  5 +-
 .../CarouselXamlGallery.xaml.cs               | 60 ++++++++++++-------
 2 files changed, 43 insertions(+), 22 deletions(-)

diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml
index 9bfad68e3db..471ff6ff319 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml
@@ -12,6 +12,7 @@
             <RowDefinition Height="Auto" />
             <RowDefinition Height="Auto" />
             <RowDefinition Height="Auto" />
+            <RowDefinition Height="Auto" />
         </Grid.RowDefinitions>
         <Grid.ColumnDefinitions>
             <ColumnDefinition />
@@ -29,9 +30,11 @@
             <Button Command="{Binding RemoveCommand}"  AutomationId="btnRemove" Text="{Binding Path=Selected.Index, StringFormat='Remove {0}'}" BackgroundColor="LightGray" TextColor="Black" />
             <Button Command="{Binding NextCommand}"  AutomationId="btnNext" Text="&gt;" FontAttributes="Bold" BackgroundColor="LightGray" TextColor="Black" />
         </StackLayout>
+        <Button Grid.Row="5" Text="Clear" Command="{Binding ClearCommand}" AutomationId="btnClear"/>
+        <Button Grid.Row="5" Grid.Column="1" Text="Set" Command="{Binding SetCommand}" AutomationId="btnSet"/>
         <CarouselView
             x:Name="carousel"
-            Grid.Row="5" Grid.ColumnSpan="2"
+            Grid.Row="6" Grid.ColumnSpan="2"
             Loop="{Binding IsLoop}"
             AutomationId="TheCarouselView"
             ItemsSource="{Binding Items}"
diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml.cs
index ee01055a2e7..6d23065af9a 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml.cs
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml.cs
@@ -35,27 +35,7 @@ public CarouselViewModel(CarouselXamlSampleType type, bool loop, int initialItem
 			IsLoop = loop;
 			_type = type;
 
-			var items = new List<CarouselItem>();
-			for (int i = 0; i < initialItems; i++)
-			{
-				switch (_type)
-				{
-					case CarouselXamlSampleType.Peek:
-						items.Add(new CarouselItem(i, "cardBackground.png"));
-						break;
-					default:
-						items.Add(new CarouselItem(i));
-						break;
-				}
-			}
-
-			MessagingCenter.Subscribe<ExampleTemplateCarousel>(this, "remove", (obj) => Items.Remove(obj.BindingContext as CarouselItem));
-
-			Items = new ObservableCollection<CarouselItem>(items);
-			Count = Items.Count - 1;
-
-			if (startCurrentItem != -1)
-				Selected = Items[startCurrentItem];
+			SetItems(initialItems, startCurrentItem);
 		}
 
 		public bool IsLoop
@@ -124,6 +104,44 @@ public CarouselItem Selected
 				Selected = newItem;
 			}
 		});
+
+		public ICommand ClearCommand => new Command(ClearItems);
+
+		public ICommand SetCommand => new Command(() =>
+		{
+			SetItems(10, 5);
+		});
+
+		void ClearItems()
+		{
+			Items.Clear();
+			Selected = null;
+		}
+
+		void SetItems(int initialItems, int startCurrentItem)
+		{
+			var items = new List<CarouselItem>();
+			for (int i = 0; i < initialItems; i++)
+			{
+				switch (_type)
+				{
+					case CarouselXamlSampleType.Peek:
+						items.Add(new CarouselItem(i, "cardBackground.png"));
+						break;
+					default:
+						items.Add(new CarouselItem(i));
+						break;
+				}
+			}
+
+			MessagingCenter.Subscribe<ExampleTemplateCarousel>(this, "remove", (obj) => Items.Remove(obj.BindingContext as CarouselItem));
+
+			Items = new ObservableCollection<CarouselItem>(items);
+			Count = Items.Count - 1;
+
+			if (startCurrentItem != -1)
+				Selected = Items[startCurrentItem];
+		}
 	}
 
 	[Preserve(AllMembers = true)]

From 20dcaf3733d9959196708eeb1e830e04a26fdf2d Mon Sep 17 00:00:00 2001
From: Rui Marinho <me@ruimarinho.net>
Date: Mon, 25 Jan 2021 20:52:41 +0000
Subject: [PATCH 2/3] [Android] Don't Scroll to item if it's null

---
 .../CarouselViewGalleries/CarouselXamlGallery.xaml.cs        | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml.cs b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml.cs
index 6d23065af9a..cb73cecd92c 100644
--- a/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml.cs
+++ b/Xamarin.Forms.Controls/GalleryPages/CollectionViewGalleries/CarouselViewGalleries/CarouselXamlGallery.xaml.cs
@@ -160,5 +160,10 @@ public CarouselItem(int index, string image = null)
 		public string Image { get; set; }
 
 		public string FeaturedImage { get; set; }
+
+		public override string ToString()
+		{
+			return Index.ToString();
+		}
 	}
 }

From 94d918d8cbbde5aee34c14764070017a56c3021d Mon Sep 17 00:00:00 2001
From: Rui Marinho <me@ruimarinho.net>
Date: Tue, 26 Jan 2021 11:17:02 +0000
Subject: [PATCH 3/3] [Android] Don't scroll if item is null

---
 .../CollectionView/CarouselViewRenderer.cs                 | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/Xamarin.Forms.Platform.Android/CollectionView/CarouselViewRenderer.cs b/Xamarin.Forms.Platform.Android/CollectionView/CarouselViewRenderer.cs
index 4bf5d6a63d6..52bb1862ac5 100644
--- a/Xamarin.Forms.Platform.Android/CollectionView/CarouselViewRenderer.cs
+++ b/Xamarin.Forms.Platform.Android/CollectionView/CarouselViewRenderer.cs
@@ -504,7 +504,12 @@ void SetCurrentItem(int carouselPosition)
 
 		void UpdateFromCurrentItem()
 		{
-			var currentItemPosition = ItemsViewAdapter.ItemsSource.GetPosition(Carousel.CurrentItem);
+			var currentItem = Carousel?.CurrentItem;
+
+			if (currentItem == null)
+				return;
+
+			var currentItemPosition = ItemsViewAdapter.ItemsSource.GetPosition(currentItem);
 			var carouselPosition = Carousel.Position;
 
 			if (_gotoPosition == -1 && currentItemPosition != carouselPosition)