dotnet / maui

.NET MAUI is the .NET Multi-platform App UI, a framework for building native device applications spanning mobile, tablet, and desktop.
https://dot.net/maui
MIT License
22.28k stars 1.76k forks source link

ListView: table cells turn black randomly #25656

Open markuspalme opened 1 month ago

markuspalme commented 1 month ago

Description

The table cells in a ListViewwhich is bound to an ObservableCollection turn black randomly after a reload:

Image

This is the full XAML for the ListView:

<ListView
                x:Name="expenseRegistrationsListView"
                Grid.Row="1"
                Grid.Column="0"
                IsRefreshing="{Binding Loading}"
                IsPullToRefreshEnabled="true"
                HasUnevenRows="True"
                ItemsSource="{Binding ExpenseRegistrations}"
                RefreshCommand="{Binding LoadCommand}"
            >
                <ListView.Behaviors>
                    <behaviors:ListViewSelectedItemBehavior
                        Command="{Binding ItemSelectedCommand}"
                        Converter="{StaticResource SelectedItemConverter}"
                     />
                </ListView.Behaviors>
                <ListView.ItemTemplate>
                    <DataTemplate x:DataType="viewmodel:ExpenseRegistrationCellViewModel">
                        <ViewCell x:Name="expenseRegistrationCell">
                            <Grid HorizontalOptions="Fill" Margin="25,5,10,0">
                                <Grid.RowDefinitions>
                                    <RowDefinition Height="*" />
                                    <RowDefinition Height="*" />
                                </Grid.RowDefinitions>

                                <Grid.ColumnDefinitions>
                                    <ColumnDefinition Width="*"/>
                                    <ColumnDefinition Width="60"/>
                                    <ColumnDefinition Width="60"/>
                                </Grid.ColumnDefinitions>

                                <Label Text="{Binding ProjectName}" FontSize="14" Grid.Row="0" Grid.Column="0" TextColor="{DynamicResource TextPrimaryColor}" />
                                <Label Text="{Binding Unit}" HorizontalTextAlignment="End" FontSize="14" Grid.Row="0" Grid.Column="1" TextColor="{DynamicResource TextPrimaryColor}" />
                                <Label Text="{Binding Quantity}" HorizontalTextAlignment="End" FontSize="14" Grid.Row="0" Grid.Column="2" TextColor="{DynamicResource TextPrimaryColor}" />
                                <Label Text="{Binding ArticleName}" FontSize="12" Grid.Row="1" Grid.Column="0" TextColor="{DynamicResource TextPrimaryColor}" />
                            </Grid>

                            <ViewCell.ContextActions>
                                <MenuItem
                                    BindingContext="{Binding Source={x:Reference expenseRegistrationsListView}, Path=BindingContext}"
                                    Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:ExpenseRegistrationViewModel}}, Path= CopyExpenseRegistrationCommand}"
                                    CommandParameter="{Binding Source={x:Reference expenseRegistrationCell}, Path=BindingContext}"
                                    Text="Kopieren"
                                    IsDestructive="false"
                                />
                                <MenuItem
                                    BindingContext="{Binding Source={x:Reference expenseRegistrationsListView}, Path=BindingContext}"
                                    Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:ExpenseRegistrationViewModel}}, Path= DeleteExpenseRegistrationCommand}"
                                    CommandParameter="{Binding Source={x:Reference expenseRegistrationCell}, Path=BindingContext}"
                                    Text="Löschen"
                                    IsDestructive="true"
                                />
                            </ViewCell.ContextActions>
                        </ViewCell>
                    </DataTemplate>
                </ListView.ItemTemplate>
            </ListView>

There are no warning about failed bindings in the debug output.

Any ideas what could cause this?

Steps to Reproduce

No response

Link to public reproduction project repository

No response

Version with bug

8.0.40 SR5

Is this a regression from previous behavior?

Yes, this used to work in Xamarin.Forms

Last version that worked well

Unknown/Other

Affected platforms

iOS

Affected platform versions

iOS 18

Did you find any workaround?

No response

Relevant log output

No response

markuspalme commented 1 month ago

The issue also reproduces with the data template being simplified to

<Label Text="{Binding ProjectName}" FontSize="14" 
    Grid.Row="0" Grid.Column="0" TextColor="{DynamicResource TextPrimaryColor}" />
jaosnz-rep commented 4 weeks ago

@markuspalme Could you provide us with a sample project so we can investigate it further? Looking forward to your reply!

mattleibow commented 3 weeks ago

Do you still have this issue if you try a CollectionView? What happens in a BindableLayout?

markuspalme commented 3 weeks ago

Here is an isolated reproduction project:

https://github.com/markuspalme/maui25656

To reproduce the issue, add some rows using the "New" button and then delete a row using the context actions:

Image

My guess is that this is related to cell caching.

markuspalme commented 3 weeks ago

Do you still have this issue if you try a CollectionView? What happens in a BindableLayout?

When I use a CollectionView like this:

<CollectionView
    x:Name="timeRegistrationsListView"
    ItemsSource="{Binding Rows}"
>
    <CollectionView.ItemTemplate>
        <DataTemplate x:DataType="viewmodel:RowModel">
            <TextCell x:Name="timeRegistrationCell" Text="{Binding Text}">
                <TextCell.ContextActions>
                    <MenuItem
                        BindingContext="{Binding Source={x:Reference timeRegistrationsListView}, Path=BindingContext}"
                        Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:TimeRegistrationViewModel}}, Path= DeleteCommand}"
                        CommandParameter="{Binding Source={x:Reference timeRegistrationCell}, Path=BindingContext}"
                        Text="Delete"
                        IsDestructive="true"
                    />
                </TextCell.ContextActions>
            </TextCell>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

I get this exception:

System.NullReferenceException: Object reference not set to an instance of an object.
   at Microsoft.Maui.Controls.Handlers.Items.TemplatedCell.Bind(DataTemplate template, Object bindingContext, ItemsView itemsView)
   at Microsoft.Maui.Controls.Handlers.Items.ItemsViewController`1[[Microsoft.Maui.Controls.ReorderableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].UpdateTemplatedCell(TemplatedCell cell, NSIndexPath indexPath)
   at Microsoft.Maui.Controls.Handlers.Items.ItemsViewController`1[[Microsoft.Maui.Controls.ReorderableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].CreateMeasurementCell(NSIndexPath indexPath)
   at Microsoft.Maui.Controls.Handlers.Items.ItemsViewController`1[[Microsoft.Maui.Controls.ReorderableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].GetPrototypeForIndexPath(NSIndexPath indexPath)
   at Microsoft.Maui.Controls.Handlers.Items.ItemsViewController`1[[Microsoft.Maui.Controls.ReorderableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].GetPrototype()
   at Microsoft.Maui.Controls.Handlers.Items.ItemsViewLayout.DetermineCellSize()
   at Microsoft.Maui.Controls.Handlers.Items.ListViewLayout.ConstrainTo(CGSize size)
   at Microsoft.Maui.Controls.Handlers.Items.ItemsViewController`1[[Microsoft.Maui.Controls.ReorderableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].CheckForEmptySource()
   at Microsoft.Maui.Controls.Handlers.Items.ItemsViewController`1[[Microsoft.Maui.Controls.ReorderableItemsView, Microsoft.Maui.Controls, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].NumberOfSections(UICollectionView collectionView)

When Is use a BindableLayout like this...

 <StackLayout BindableLayout.ItemsSource="{Binding Rows}"
             Orientation="Horizontal"
             x:Name="timeRegistrationsListView"
>
    <BindableLayout.ItemTemplate>
        <DataTemplate x:DataType="viewmodel:RowModel">
            <TextCell x:Name="timeRegistrationCell" Text="{Binding Text}">
                <TextCell.ContextActions>
                    <MenuItem
                        BindingContext="{Binding Source={x:Reference timeRegistrationsListView}, Path=BindingContext}"
                        Command="{Binding Source={RelativeSource AncestorType={x:Type viewmodel:TimeRegistrationViewModel}}, Path= DeleteCommand}"
                        CommandParameter="{Binding Source={x:Reference timeRegistrationCell}, Path=BindingContext}"
                        Text="Delete"
                        IsDestructive="true"
                    />
                </TextCell.ContextActions>
            </TextCell>
        </DataTemplate>
    </BindableLayout.ItemTemplate>
</StackLayout>

I get this exception:

System.InvalidCastException: Specified cast is not valid.
   at Microsoft.Maui.Controls.BindableLayoutController.CreateItemView(Object item, DataTemplate dataTemplate)
   at Microsoft.Maui.Controls.BindableLayoutController.CreateItemView(Object item, IBindableLayout layout)
   at Microsoft.Maui.Controls.BindableLayoutController.<>c__DisplayClass40_0.<ItemsSourceCollectionChanged>b__0(Object item, Int32 index, Boolean _)
   at Microsoft.Maui.Controls.Internals.NotifyCollectionChangedEventArgsExtensions.Apply(NotifyCollectionChangedEventArgs self, Action`3 insert, Action`2 removeAt, Action reset)
   at Microsoft.Maui.Controls.BindableLayoutController.ItemsSourceCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
   at Microsoft.Maui.Controls.WeakNotifyCollectionChangedProxy.OnCollectionChanged(Object sender, NotifyCollectionChangedEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1[[TestApp.Maui.ViewModels.RowModel, TestApp.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnCollectionChanged(NotifyCollectionChangedEventArgs e)
   at System.Collections.ObjectModel.ObservableCollection`1[[TestApp.Maui.ViewModels.RowModel, TestApp.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].OnCollectionChanged(NotifyCollectionChangedAction action, Object item, Int32 index)
   at System.Collections.ObjectModel.ObservableCollection`1[[TestApp.Maui.ViewModels.RowModel, TestApp.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].InsertItem(Int32 index, RowModel item)
   at System.Collections.ObjectModel.Collection`1[[TestApp.Maui.ViewModels.RowModel, TestApp.Maui, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null]].Add(RowModel item)
   at TestApp.Maui.ViewModels.TimeRegistrationViewModel.Load() in /Users/markus/Source/Maui25656/TestApp/ViewModels/TimeRegistrationViewModel.cs:line 48
   at CommunityToolkit.Mvvm.Input.AsyncRelayCommand.AwaitAndThrowIfFailed(Task executionTask)
   at System.Threading.Tasks.Task.<>c.<ThrowAsync>b__128_0(Object state)
   at Foundation.NSAsyncSynchronizationContextDispatcher.Apply() in /Users/builder/azdo/_work/1/s/xamarin-macios/src/Foundation/NSAction.cs:line 179

Seems like it's not possible to use a TextCell in these containers.

jaosnz-rep commented 3 weeks ago

I can repro this issue at iOS platform on the latest 17.13.0 Preview 1.0(8.0.93 & 8.0.92 & 8.0.40).

mattleibow commented 2 weeks ago

Ah, yeah. You can't use the cells in anything other than ListView.

Can you try using just a label in CollectionView and BindableLayout?

markuspalme commented 2 weeks ago

@mattleibow I can't reproduce it with a CollectionView, see branch collectionview in my test repo.

https://github.com/markuspalme/maui25656/tree/collectionview