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
21.9k stars 1.69k forks source link

MAUI on Android - when using ListView & ViewCell rows can appear in wrong order or sometimes be blank #22901

Open Enigma86d opened 1 month ago

Enigma86d commented 1 month ago

Description

In xaml create a StackLayout and inside it a ListView which uses ViewCell. in the ViewCell put a Grid with one row and 4 columns (to hold 4 Labels). Give the ListView a relatively small height, say 100 so that the ListView would scroll vertically. In C# create a observable collection and assign it to the ItemsSource of the ListView. Add 10 items to the collection. When scrolling and tapping the ListView, some rows appear in wrong order. Also, very unfrequently, a random row may become blank, showing just a color (without any contents from the observable collection). Video showing the problem: https://www.youtube.com/watch?v=pr3PCIkgsyg At 4 min 25 sec, empty rows appear in the table: https://www.youtube.com/watch?v=pr3PCIkgsyg&t=265s The problem doesn't seem to appear on iOS.

Steps to Reproduce

  1. Create a .NET8 MAUI project.
  2. In XAML write a StackLayout and inside it a ListView with a HeightRequest of 100.
  3. Define a ViewCell which contains a Grid with one row and 4 columns.
  4. In C# create a observable collection of a class that contains 4 string properties.
  5. Assign the colleciton to the ItemsSource of the ListView
  6. Add 10 items to the observable collection

Link to public reproduction project repository

https://github.com/Enigma86d/ListViewBug

Version with bug

8.0.40 SR5

Is this a regression from previous behavior?

Code worked in Xamarin Forms

Last version that worked well

Unknown/Other

Affected platforms

Android

Affected platform versions

Tested on Android 12 & 8.1.0

Did you find any workaround?

No workaround found.

Relevant log output

No response

XAML

<?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"
             x:Class="ListViewTest.MainPage">

    <StackLayout Orientation="Vertical" Margin="10">

        <ListView x:Name="MyListView"
                              HeightRequest="100"
                              VerticalOptions="Center"
                              HasUnevenRows="True"
                              BackgroundColor="LightBlue"
                              Margin="0, 0, 0, 10">
            <ListView.ItemTemplate>
                <DataTemplate>
                    <ViewCell>
                        <Grid BackgroundColor="#404040"
                                          Margin="0"
                                          ColumnSpacing="0">
                            <Grid.ColumnDefinitions>
                                <ColumnDefinition Width="1*"/>
                                <ColumnDefinition Width="1*"/>
                                <ColumnDefinition Width="1*"/>
                                <ColumnDefinition Width="1*"/>
                            </Grid.ColumnDefinitions>
                            <Label Grid.Column="0"
                                    BackgroundColor="#F0F0F0"
                                    Margin="1"
                                    HorizontalTextAlignment="Start"
                                    FontSize="16"
                                    Text="{Binding Item1, StringFormat='{0}'}"/>
                            <Label Grid.Column="1"
                                    BackgroundColor="#F0F0F0"
                                    Margin="1"
                                    HorizontalTextAlignment="Center"
                                    FontSize="16"
                                    Text="{Binding Item2, StringFormat='{0}'}"/>
                            <Label Grid.Column="2"
                                    BackgroundColor="#F0F0F0"
                                    Margin="1"
                                    HorizontalTextAlignment="Center"
                                    FontSize="16"
                                    Text="{Binding Item3, StringFormat='{0}'}"/>
                            <Label Grid.Column="3"
                                    BackgroundColor="#F0F0F0"
                                    Margin="1"
                                    HorizontalTextAlignment="Center"
                                    FontSize="16"
                                    Text="{Binding Item4, StringFormat='{0}'}"/>
                        </Grid>
                    </ViewCell>
                </DataTemplate>
            </ListView.ItemTemplate>
        </ListView>

    </StackLayout>

</ContentPage>

C#

using ListViewTest.models;

namespace ListViewTest
{
    public partial class MainPage : ContentPage
    {
        private MeasurementCollection data = new MeasurementCollection();

        public MainPage()
        {
            InitializeComponent();

            MyListView.ItemsSource = data;
            data.Add(new Measurement(0));
            data.Add(new Measurement(1));
            data.Add(new Measurement(2));
            data.Add(new Measurement(3));
            data.Add(new Measurement(4));
            data.Add(new Measurement(5));
            data.Add(new Measurement(6));
            data.Add(new Measurement(7));
            data.Add(new Measurement(8));
            data.Add(new Measurement(9));
        }

    }

}

C#

using System.Collections.ObjectModel;

namespace ListViewTest.models
{
    public class Measurement
    {
        public string Item1 { get; set; }
        public string Item2 { get; set; }
        public string Item3 { get; set; }
        public string Item4 { get; set; }

        public Measurement(int no)
        {
            Item1 = no.ToString();
            Item2 = (no+10).ToString();
            Item3 = (no+100).ToString();
            Item4 = (no + 1000).ToString();
        }
    }

    public class MeasurementCollection : ObservableCollection<Measurement>
    {
        public MeasurementCollection()
        {
        }
    }

}
github-actions[bot] commented 1 month ago

Hi I'm an AI powered bot that finds similar issues based off the issue title.

Please view the issues below to see if they solve your problem, and if the issue describes your problem please consider closing this one and thumbs upping the other issue to help us prioritize it. Thank you!

Open similar issues:

Closed similar issues:

Note: You can give me feedback by thumbs upping or thumbs downing this comment.

ninachen03 commented 1 month ago

Verified this issue with Visual Studio 17.11.0 Preview 1.1(8.0.40 & 8.0.3). Can repro it. image

millslf commented 1 month ago

According to some of the linked issues(#16137 and #16669), changing to CollectionView is a solution, this however:

  1. Introduces a host of other problems on our iOS build.
  2. The performance seems a lot worse than on the ListView. (Not that Listview is great when using RetainElement cachingStrategy, more on that later) ListView, imo is the way to go on iOS.

Some other things that we have noticed that might be relevant:

  1. CachingStrategy seems to have a rather big effect as well, using the default RetainElement is the most stable, the other 2 more aggressive strategies makes this problem significantly more noticeable.
  2. When using these other non-default CachingStrategies, iOS is also affected, particularly without SetGroupHeaderStyle set to grouped, and SetRowAnimationsEnabled set to false.
PureWeen commented 1 month ago

For the original sample if you put it inside a Grid vs a StackLayout do you see a better result?

If you're only having issues on Android can you use a CollectionView on Android and ListView on iOS for now so that you can release?

CollectionView on Android should work remarkably better

Enigma86d commented 1 month ago

I am just about to leave for a week long holiday and I don't have any spare time to test, but I rememebr testing witout a stack layout (having just a ListView) and I remember that there were similar problems, but they appeared much less frequent. I will test again though when I return.

jonathanantoine commented 3 weeks ago

I have the same exact issue, any work around exists ?

Enigma86d commented 3 weeks ago

Just checked my MAUI notes and paste the relevant ones here: • ListView (Android only): when it has a “RequestHeight” set and list scrolls, rows can appear in wrong order • ListView / CollectionView: cannot have any stack layout as parent because it will not scroll https://github.com/dotnet/maui/issues/14955 • CollectionView: runs slower than ListView + cannot pin header at top https://github.com/dotnet/maui/issues/17719; also, header seems to overflow horizontally on iOS…

Thus, the solution I adopted was to use a CollectionView which doesn't have a stack layout as any of it's parents (use Grids instead...) + because I had some issues with its header, I made a separate grid above the CollectionView instead of using its header. This solution works ok on both Android and iOS, but note that I don't have the requirment of horizontal scrooling (I am using just vertical scrool). If you need horizontal scrooling, then my solution may not be good enough.