Fix crash using the CarouselView and EmptyView (#8430)
authorJavier Suárez Ruiz <javiersuarezruiz@hotmail.com>
Tue, 19 Nov 2019 10:24:53 +0000 (11:24 +0100)
committerGerald Versluis <gerald.versluis@microsoft.com>
Tue, 19 Nov 2019 10:24:53 +0000 (11:24 +0100)
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue8417.xaml [new file with mode: 0755]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue8417.xaml.cs [new file with mode: 0755]
Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Xamarin.Forms.Controls.Issues.Shared.projitems
Xamarin.Forms.Platform.Android/CollectionView/DataChangeObserver.cs

diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue8417.xaml b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue8417.xaml
new file mode 100755 (executable)
index 0000000..55a79c3
--- /dev/null
@@ -0,0 +1,59 @@
+<?xml version="1.0" encoding="utf-8" ?>
+<controls:TestContentPage 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"
+             xmlns:controls="clr-namespace:Xamarin.Forms.Controls"
+             mc:Ignorable="d"
+             x:Class="Xamarin.Forms.Controls.Issues.Issue8417"
+             Title="Issue 8417" >
+    <ContentPage.Content>
+        <StackLayout>
+            <Label
+                BackgroundColor="Black"
+                TextColor="White"
+                Text="Wait for the items to appear and hit the on screen back button. If navigate back without problems, the test passes."/>
+           <CarouselView
+               x:Name="carouselView"
+                EmptyView="Loading items simulation.">
+                <CarouselView.ItemTemplate>
+                    <DataTemplate>
+                        <StackLayout>
+                            <Frame HasShadow="True"
+                                    BorderColor="DarkGray"
+                                    CornerRadius="5"
+                                    Margin="20"
+                                    HeightRequest="300"
+                                    HorizontalOptions="Center"
+                                    VerticalOptions="CenterAndExpand">
+                                <StackLayout>
+                                    <Label
+                                        Text="{Binding Name}" 
+                                        FontAttributes="Bold"
+                                        FontSize="Large"
+                                        HorizontalOptions="Center"
+                                        VerticalOptions="Center" />
+                                    <Image
+                                        Source="{Binding ImageUrl}" 
+                                        Aspect="AspectFill"
+                                        HeightRequest="150"
+                                        WidthRequest="150"
+                                        HorizontalOptions="Center" />
+                                    <Label
+                                        Text="{Binding Location}"
+                                        HorizontalOptions="Center" />
+                                    <Label
+                                        Text="{Binding Details}"
+                                        FontAttributes="Italic"
+                                        HorizontalOptions="Center"
+                                        MaxLines="5"
+                                        LineBreakMode="TailTruncation" />
+                                </StackLayout>
+                            </Frame>
+                        </StackLayout>
+                    </DataTemplate>
+                </CarouselView.ItemTemplate>
+           </CarouselView>
+        </StackLayout>
+    </ContentPage.Content>
+</controls:TestContentPage>
\ No newline at end of file
diff --git a/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue8417.xaml.cs b/Xamarin.Forms.Controls.Issues/Xamarin.Forms.Controls.Issues.Shared/Issue8417.xaml.cs
new file mode 100755 (executable)
index 0000000..20f52e5
--- /dev/null
@@ -0,0 +1,96 @@
+using System.Collections.Generic;
+using Xamarin.Forms.CustomAttributes;
+using Xamarin.Forms.Internals;
+using System.Collections.ObjectModel;
+using System.Threading.Tasks;
+
+#if UITEST
+using Xamarin.UITest;
+using NUnit.Framework;
+using Xamarin.UITest.iOS;
+#endif
+
+namespace Xamarin.Forms.Controls.Issues
+{
+       [Preserve(AllMembers = true)]
+       [Issue(IssueTracker.Github, 8417, "(Android) CarouselView Java.Lang.IllegalStateException", PlatformAffected.Android)]
+       public partial class Issue8417 : TestContentPage
+       {
+               public Issue8417()
+               {
+#if APP
+                       Device.SetFlags(new List<string> { ExperimentalFlags.CarouselViewExperimental });
+                       InitializeComponent();
+                       BindingContext = new Issue8417ViewModel();
+#endif
+               }
+
+               protected override void Init()
+               {
+
+               }
+
+               protected override async void OnAppearing()
+               {
+                       base.OnAppearing();
+
+                       await Task.Delay(2000);
+#if APP
+                       carouselView.ItemsSource = (BindingContext as Issue8417ViewModel).Items;
+#endif
+               }
+       }
+
+       [Preserve(AllMembers = true)]
+       public class Issue8417Model
+       {
+               public string Name { get; set; }
+               public string Location { get; set; }
+               public string Details { get; set; }
+               public string ImageUrl { get; set; }
+       }
+
+       [Preserve(AllMembers = true)]
+       public class Issue8417ViewModel : BindableObject
+       {
+               readonly IList<Issue8417Model> _items;
+
+               public ObservableCollection<Issue8417Model> Items { get; private set; }
+
+               public Issue8417ViewModel()
+               {
+                       _items = new List<Issue8417Model>();
+
+                       CreateCollection();
+               }
+
+               void CreateCollection()
+               {
+                       _items.Add(new Issue8417Model
+                       {
+                               Name = "Baboon",
+                               Location = "Africa & Asia",
+                               Details = "Baboons are African and Arabian Old World monkeys belonging to the genus Papio, part of the subfamily Cercopithecinae.",
+                               ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/f/fc/Papio_anubis_%28Serengeti%2C_2009%29.jpg/200px-Papio_anubis_%28Serengeti%2C_2009%29.jpg"
+                       });
+
+                       _items.Add(new Issue8417Model
+                       {
+                               Name = "Capuchin Monkey",
+                               Location = "Central & South America",
+                               Details = "The capuchin monkeys are New World monkeys of the subfamily Cebinae. Prior to 2011, the subfamily contained only a single genus, Cebus.",
+                               ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/4/40/Capuchin_Costa_Rica.jpg/200px-Capuchin_Costa_Rica.jpg"
+                       });
+
+                       _items.Add(new Issue8417Model
+                       {
+                               Name = "Blue Monkey",
+                               Location = "Central and East Africa",
+                               Details = "The blue monkey or diademed monkey is a species of Old World monkey native to Central and East Africa, ranging from the upper Congo River basin east to the East African Rift and south to northern Angola and Zambia",
+                               ImageUrl = "http://upload.wikimedia.org/wikipedia/commons/thumb/8/83/BlueMonkey.jpg/220px-BlueMonkey.jpg"
+                       });
+
+                       Items = new ObservableCollection<Issue8417Model>(_items);
+               }
+       }
+}
\ No newline at end of file
index a4cc51d..b613896 100644 (file)
     <Compile Include="$(MSBuildThisFileDirectory)Issue7898.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue7249.cs" />
     <Compile Include="$(MSBuildThisFileDirectory)Issue8200.cs" />
+    <Compile Include="$(MSBuildThisFileDirectory)Issue8417.xaml.cs" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla22229.xaml">
     <EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue7886.xaml">
       <Generator>MSBuild:UpdateDesignTimeXaml</Generator>
     </EmbeddedResource>
+    <EmbeddedResource Include="$(MSBuildThisFileDirectory)Issue8417.xaml" />
   </ItemGroup>
   <ItemGroup>
     <EmbeddedResource Include="$(MSBuildThisFileDirectory)Bugzilla27417Xaml.xaml">
index 8d4d7a5..aa50d12 100644 (file)
@@ -7,7 +7,9 @@ namespace Xamarin.Forms.Platform.Android
 {
        internal class DataChangeObserver : RecyclerView.AdapterDataObserver
        {
+               IntPtr _adapter;
                readonly Action _onDataChange;
+
                public bool Observing { get; private set; }
 
                public DataChangeObserver(Action onDataChange) : base()
@@ -23,16 +25,19 @@ namespace Xamarin.Forms.Platform.Android
                        }
 
                        adapter.RegisterAdapterDataObserver(this);
+
+                       _adapter = adapter.Handle;
                        Observing = true;
                }
 
                public void Stop(Adapter adapter)
                {
-                       if (Observing && adapter != null && adapter.HasObservers)
+                       if (Observing && IsValidAdapter(adapter))
                        {
                                adapter.UnregisterAdapterDataObserver(this);
                        }
 
+                       _adapter = IntPtr.Zero;
                        Observing = false;
                }
 
@@ -71,5 +76,10 @@ namespace Xamarin.Forms.Platform.Android
                        base.OnItemRangeMoved(fromPosition, toPosition, itemCount);
                        _onDataChange?.Invoke();
                }
+
+               bool IsValidAdapter(Adapter adapter)
+               {
+                       return adapter != null && adapter.Handle == _adapter && adapter.HasObservers;
+               }
        }
 }
\ No newline at end of file