Description
Description
In Android only, starting from Maui 8.0.6 SR1 and continues to at least 8.0.20 SR4 (might be in 8.0.21 SR4.1 but haven't tested that one EDIT: it is still in 8.0.21 SR4.1), an exception occurs when adding items to the ObservableCollection backing a CarouselView after having navigated to the same page for a second time. This is very similar to what used to happen to Collection Views in .NET 7 as chronicled in #12219 (and fixed in #13385), except now it happens for CarouselViews. Case-in-point, my repro project is merely an updated and modified version of jaldinger's repro project from back in that issue, and it manifests the same behavior for CarouselViews now as it did for CollectionViews back then (I have verified that CollectionViews do not experience this issue anymore, so the previous bugfix hasn't been regressed).
carousel_virtualview_error.mp4
Occurs in 8.0.21 SR 4.1, 8.0.20 SR4, 8.0.14 SR3.1, 8.0.10 SR3, 8.0.7 SR2, Might be in the newest 8.0.21 SR 4.1 but haven't tested that one yet since it just came out hours ago. It is tested now
Steps to Reproduce
- Create a File > New .NET MAUI App
- Add a second ContentPage to the project, named "Page2"
- In AppShell.xaml.cs add: Routing.RegisterRoute("Page2", typeof(Page2));
- In MauiProgram.cs add: builder.Services.AddScoped();
- Add a class to the project called "Foo" and populate it as follows:
public class Foo
{
public string ImagePath { get; set; }
}
- Copy all the images from here and paste them in your project's Resources/Images folder
- In Page2.xaml replace all the content with:
<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
xmlns:local="clr-namespace:MauiAppRepro1"
x:Class="MauiAppRepro1.Page2"
x:DataType="local:Page2"
Title="Page2"
x:Name="this"
BindingContext="{x:Reference this}">
<VerticalStackLayout>
<CarouselView ItemsSource="{Binding FooImages}" MaximumHeightRequest="150">
<CarouselView.ItemTemplate>
<DataTemplate x:DataType="local:Foo">
<VerticalStackLayout>
<Image Source="{Binding ImagePath}" />
</VerticalStackLayout>
</DataTemplate>
</CarouselView.ItemTemplate>
</CarouselView>
<Button
Text="Load items"
Pressed="Button_Pressed" />
</VerticalStackLayout>
</ContentPage>
- In Page2.xaml.cs replace the class with:
public partial class Page2 : ContentPage
{
public ObservableCollection<Foo> FooImages { get; set; } = new();
public Page2()
{
InitializeComponent();
this.BindingContext = this;
}
private async void Button_Pressed(object sender, EventArgs e)
{
FooImages.Clear();
await Task.Delay(1000);
FooImages.Add(new Foo { ImagePath = "red_mm.png" });
FooImages.Add(new Foo { ImagePath = "yellow_mm.png" });
FooImages.Add(new Foo { ImagePath = "blue_mm.png" });
FooImages.Add(new Foo { ImagePath = "orange_mm.png" });
}
}
- In MainPage.xaml.cs modify OnCounterClicked as follows:
private async void OnCounterClicked(object sender, EventArgs e)
{
count++;
if (count == 1)
CounterBtn.Text = $"Clicked {count} time";
else
CounterBtn.Text = $"Clicked {count} times";
SemanticScreenReader.Announce(CounterBtn.Text);
await Shell.Current.GoToAsync("/Page2");
}
- Run the app on Android
- Click the button on MainPage
- Click the button on Page2 two or more times --> works fine
- Go back to MainPage
- Click the button on MainPage again
- Click the button on Page2 --> Exception occurs:
**System.InvalidOperationException:** 'VirtualView cannot be null here'
Link to public reproduction project repository
https://github.com/RedZone908/CarouselVirtualViewErrorRepro/tree/master
Version with bug
8.0.6 SR1
Is this a regression from previous behavior?
Yes, this used to work in .NET MAUI
Last version that worked well
8.0.3 GA
Affected platforms
Android
Affected platform versions
Android 21 and up
Did you find any workaround?
Simply instantiating a new ObservableCollection
in the page's OnAppearing
handler instead of reusing the existing one will not trigger the error.
Relevant log output
**System.InvalidOperationException:** 'VirtualView cannot be null here'
[libc] Requested dump for pid 17324 (e.mauiapprepro1)
**System.InvalidOperationException:** 'VirtualView cannot be null here'
[mono-rt] [ERROR] FATAL UNHANDLED EXCEPTION: System.InvalidOperationException: VirtualView cannot be null here
[mono-rt] at Microsoft.Maui.Handlers.ViewHandler`2[[Microsoft.Maui.Controls.CarouselView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[AndroidX.RecyclerView.Widget.RecyclerView, Xamarin.AndroidX.RecyclerView, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].get_VirtualView() in D:\a\_work\1\s\src\Core\src\Handlers\View\ViewHandlerOfT.cs:line 42
[mono-rt] at Microsoft.Maui.Controls.Handlers.Items.CarouselViewHandler.CreateAdapter() in D:\a\_work\1\s\src\Controls\src\Core\Handlers\Items\CarouselViewHandler.Android.cs:line 17
[mono-rt] at Microsoft.Maui.Controls.Handlers.Items.MauiRecyclerView`3[[Microsoft.Maui.Controls.CarouselView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Controls.Handlers.Items.ItemsViewAdapter`2[[Microsoft.Maui.Controls.CarouselView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Controls.Handlers.Items.IItemsViewSource, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]], Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null],[Microsoft.Maui.Controls.Handlers.Items.IItemsViewSource, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].UpdateAdapter() in D:\a\_work\1\s\src\Controls\src\Core\Handlers\Items\Android\MauiRecyclerView.cs:line 236
[mono-rt] at Microsoft.Maui.Controls.Handlers.Items.MauiCarouselRecyclerView.UpdateAdapter() in D:\a\_work\1\s\src\Controls\src\Core\Handlers\Items\Android\MauiCarouselRecyclerView.cs:line 140
[mono-rt] at Microsoft.Maui.Controls.Handlers.Items.MauiCarouselRecyclerView.CollectionItemsSourceChanged(Object sender, NotifyCollectionChangedEventArgs e) in D:\a\_work\1\s\src\Controls\src\Core\Handlers\Items\Android\MauiCarouselRecyclerView.cs:line 251
[mono-rt] at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.CollectionChanged(NotifyCollectionChangedEventArgs args) in D:\a\_work\1\s\src\Controls\src\Core\Handlers\Items\Android\ItemsSources\ObservableItemsSource.cs:line 131
[mono-rt] at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.<>c__DisplayClass33_0.<CollectionChanged>b__0() in D:\a\_work\1\s\src\Controls\src\Core\Handlers\Items\Android\ItemsSources\ObservableItemsSource.cs:line 106
[mono-rt] at Microsoft.Maui.Controls.DispatcherExtensions.DispatchIfRequired(IDispatcher dispatcher, Action action) in D:\a\_work\1\s\src\Controls\src\Core\DispatcherExtensions.cs:line 59
[mono-rt] at Microsoft.Maui.Controls.Handlers.Items.ObservableItemsSource.CollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) in D:\a\_work\1\s\src\Controls\src\Core\Handlers\Items\Android\ItemsSources\ObservableItemsSource.cs:line 106
[mono-rt] at Microsoft.Maui.Controls.WeakNotifyCollectionChangedProxy.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e) in D:\a\_work\1\s\src\Controls\src\Core\Internals\WeakEventProxy.cs:line 78
[mono-rt] at Microsoft.Maui.Controls.MarshalingObservableCollection.OnCollectionChanged(NotifyCollectionChangedEventArgs args) in D:\a\_work\1\s\src\Controls\src\Core\Items\MarshalingObservableCollection.cs:line 49
[mono-rt] at Microsoft.Maui.Controls.MarshalingObservableCollection.Reset(NotifyCollectionChangedEventArgs args) in D:\a\_work\1\s\src\Controls\src\Core\Items\MarshalingObservableCollection.cs:line 152
[mono-rt] at Microsoft.Maui.Controls.MarshalingObservableCollection.HandleCollectionChange(NotifyCollectionChangedEventArgs args) in D:\a\_work\1\s\src\Controls\src\Core\Items\MarshalingObservableCollection.cs:line 85
[mono-rt] at Microsoft.Maui.Controls.MarshalingObservableCollection.<>c__DisplayClass8_0.<InternalCollectionChanged>b__0() in D:\a\_work\1\s\src\Controls\src\Core\Items\MarshalingObservableCollection.cs:line 65
[mono-rt] at Microsoft.Maui.Controls.DispatcherExtensions.DispatchIfRequired(IDispatcher dispatcher, Action action) in D:\a\_work\1\s\src\Controls\src\Core\DispatcherExtensions.cs:line 59
[mono-rt] at Microsoft.Maui.Controls.MarshalingObservableCollection.InternalCollectionChanged(Object sender, NotifyCollectionChangedEventArgs args) in D:\a\_work\1\s\src\Controls\src\Core\Items\MarshalingObservableCollection.cs:line 65
[mono-rt] at System.Collections.ObjectModel.ObservableCollection`1[[MauiAppRepro1.Foo, MauiAppRepro1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnCollectionChanged(NotifyCollectionChangedEventArgs e)
[mono-rt] at System.Collections.ObjectModel.ObservableCollection`1[[MauiAppRepro1.Foo, MauiAppRepro1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnCollectionReset()
[mono-rt] at System.Collections.ObjectModel.ObservableCollection`1[[MauiAppRepro1.Foo, MauiAppRepro1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].ClearItems()
[mono-rt] at System.Collections.ObjectModel.Collection`1[[MauiAppRepro1.Foo, MauiAppRepro1, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].Clear()
[mono-rt] at MauiAppRepro1.Page2.Button_Pressed(Object sender, EventArgs e) in C:\repos\GitIssues\MauiAppRepro1.App\Page2.xaml.cs:line 18
[mono-rt] at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state)
[mono-rt] at Android.App.SyncContext.<>c__DisplayClass2_0.<Post>b__0() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.App/SyncContext.cs:line 36
[mono-rt] at Java.Lang.Thread.RunnableImplementor.Run() in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Java.Lang/Thread.cs:line 36
[mono-rt] at Java.Lang.IRunnableInvoker.n_Run(IntPtr jnienv, IntPtr native__this) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/obj/Release/net8.0/android-34/mcw/Java.Lang.IRunnable.cs:line 84
[mono-rt] at Android.Runtime.JNINativeWrapper.Wrap_JniMarshal_PP_V(_JniMarshal_PP_V callback, IntPtr jnienv, IntPtr klazz) in /Users/runner/work/1/s/xamarin-android/src/Mono.Android/Android.Runtime/JNINativeWrapper.g.cs:line 26
Metadata
Assignees
Labels
Type
Projects
Status
Done