maui icon indicating copy to clipboard operation
maui copied to clipboard

.NET MAUI RC1 - CollectionView extremely slow

Open Sergtek opened this issue 2 years ago • 49 comments

Description

Doing some tests with the CollectionView I have realized that the control is extremely slow in .NET Maui, I have added a DataTemplate with several elements to simulate a scenario as close to reality (production environment) and I have realized that something is not It is working well since the more items the ObservableCollection has linked to the ItemsSource and the more items the CollectionView has to render, the slower the application starts, the only thing that occurs to me is that the CollectionView recycling system is not working correctly and render all the CollectionView items at the same time, I have created an identical repository in Xamarin.Forms with 9999 items in the CollectionView and everything works fast and well, however in .NET Maui the same case but only with 300 items takes 2:20 minutes in start the app.

When you go to do the tests, all you have to do is go to the MainPageViewModel class and in the constructor there is a loop that is in charge of initializing the ObservableCollection linked to the CollectionView, by default it is configured in 300 elements, which more or less will do that the app takes about 2:20 seconds to start completely, even when it starts after that time there is a little lag if you try to scroll in the CollectionView until a few seconds pass and the performance stabilizes. I recommend lowering that number to 50 or 100 for faster testing in .NET Maui. In the Xamarin.Forms repository it is set to 9999 items and the performance is perfect and fast, probably because the Xamarin.Forms recycling system works fine.

Loop image:

error01

I leave the 2 GitHub repositories in case you need to do tests:

  • .Net Maui: https://github.com/nacompllo/MauiCollectionView

  • Xamarin.Forms: https://github.com/nacompllo/XamarinCollectionView

Steps to Reproduce

Download the attached repository and follow the instructions detailed above.

Version with bug

Release Candidate 1 (current)

Last version that worked well

Unknown/Other

Affected platforms

Android, I was not able test on other platforms

Affected platform versions

Android 10

Did you find any workaround?

No response

Relevant log output

No response

Sergtek avatar Apr 20 '22 14:04 Sergtek

It will probably work fine if you remove outer VerticalStackLayout.

Dreamescaper avatar Apr 20 '22 23:04 Dreamescaper

It will probably work fine if you remove outer VerticalStackLayout.

I've tried it but the problem still occurs. I would bet more that it is a problem with the recycling of CollectionView elements since the more items the ItemSource has and the more controls the DataTemplate has the slower the startup is because it probably proceeds to render all the controls of all the items of the CollectionView.

Sergtek avatar Apr 21 '22 06:04 Sergtek

Ok, I had a similar issue, but caused by the stack layout - it allows collectionView to grow infinitely, and therefore render all the items. It was closed as not a bug, unfortunately :(

Probably this one is different though, if it didn't help for you.

Dreamescaper avatar Apr 21 '22 06:04 Dreamescaper

Btw, you don't need an outer ScrollLayout either, CollectionView is already scrollable.

Dreamescaper avatar Apr 21 '22 06:04 Dreamescaper

Ok, I had a similar issue, but caused by the stack layout - it allows collectionView to grow infinitely, and therefore render all the items. It was closed as not a bug, unfortunately :(

Probably this one is different though, if it didn't help for you.

Btw, you don't need an outer ScrollLayout either, CollectionView is already scrollable.

As far as I see something similar has happened to me, since removing the ScrollView works correctly, probably what you said is that with the ScrollView allowed the CollectionView to grow infinitely until all its elements are rendered. This doesn't seem very appropriate, does it make sense for the CollectionView to grow infinitely when it is inside a ScrollView, can this thread be closed, or is it a bug?

Sergtek avatar Apr 21 '22 07:04 Sergtek

I think the important thing is here is that it works well in Forms. Then it should also work in .NET MAUI as far as I'm concerned :)

jfversluis avatar Apr 21 '22 07:04 jfversluis

Additional note: The CollectionView only grows infinitely when it's inside a ScrollView or VerticalStackLayout. With the rest of the Layouts it does not happen.

Sergtek avatar Apr 21 '22 07:04 Sergtek

I try https://github.com/nacompllo/MauiCollectionView on android emulator. It takes about 1 minute to initialize.

VincentBu avatar Apr 26 '22 07:04 VincentBu

Hello, I was looking what was I missing because the same code run in a blink of an eye on Xamarin Forms but on MAUI.... A simple collection of 3000 items takes 5 seconds to render on a real device while it was something like 0.1/0.2 on Xamarin Forms.

And don't even try to scroll on a ListView/CollectionView of more than 100 items : you definitively see the caching strategy in action : it freezes and jerks each time a new line appears on screen...

nk54 avatar Jun 03 '22 13:06 nk54

ouh i hope there is coming a fix soon. ListView and CollectionView is so incredible slowly.

For tests i run my Views only in a Grid without anything around, use only "10" items and have just the same issue as the Thread Owner. I cant scroll without lag time from 1-2 seconds. Xamarin was so smooth <3

Cant understand why this isnt fixed right now.

Steven-L-42 avatar Aug 03 '22 14:08 Steven-L-42

Do you have an ETA on this issue? I'm struggling to use my app especially on low spec devices due to this issue.

kojini avatar Aug 10 '22 08:08 kojini

We've moved this issue to the Backlog milestone. This means that it is not going to be worked on for the coming release. We will reassess the backlog following the current release and consider this item at that time. To learn more about our issue management process and to have better expectation regarding different types of issues you can read our Triage Process.

ghost avatar Aug 29 '22 20:08 ghost

I am having the same issue with 1k items it is taking well over 10 minutes to load on an emulator and my datatemplate is simple

the collectionview is housed in a MAUI toolkit Popup here is what the xaml would look like the contentView is a seperate file that is shared between a contacts page and a new message popup where the issue occurs.

<toolkit:Popup>
 <Grid>
  <ContentView>
   <Grid>
    <Grid>
     <CollectionView>
      <DataTemplate>
       <Grid>
        <Label>
        <Label>
       </Grid>
      </DataTemplate>
     </CollectionView>
    </Grid>
   </Grid>
  </ContentView>
 </Grid>
</toolkit:Popup> 

If i do not house this collectionview in a popup page then it renders quickly

LennoxP90 avatar Sep 12 '22 17:09 LennoxP90

@nacompllo I'm looking at your sample:

https://github.com/nacompllo/MauiCollectionView

It puts dotnet_bot.svg 3 times for each row. This is a 672x832 image squashed into a tiny <ImageButton/>.

Can you use a different image, maybe one that is sized appropriately for the space inside a button?

I'll remove the images and profile what I see for now.

jonathanpeppers avatar Sep 14 '22 20:09 jonathanpeppers

@PureWeen @hartez would you know why the above example seems like it might be rendering every row in the CollectionView? Should it only be doing this for the elements visible? Is CollectionView "virtualized"?

The app start times for me on a Pixel 5 are:

.NET 6: 16s412ms
.NET 7: 14s642ms

There does appear to be a goldmine of things to optimize in here: collectionview.zip

(The trace ending in 637 is .NET 6, and 947 is .NET 7)

jonathanpeppers avatar Sep 14 '22 21:09 jonathanpeppers

@jonathanpeppers this hierarchy feels problematic

    <ScrollView>
        <VerticalStackLayout>
            <CollectionView 

If you just put the CollectionView as the root of the page, change VSL to a `Grid', or set the height of the CV does it perform better?

The thing about the VSL is that it has infinite height so it has no idea what height to give the CollectionView. The StackLayout in MAUI works different that FORMS but it's now consistent with UWP.

If you put a CV inside a VSL the VSL basically tells the RecyclerView hey you have infinite space to exist in so the RecyclerView says cool I'm gong to create all my rows.

From the XAML it seems like the ScrollView was added to compensate for the behavior of the VSL?

PureWeen avatar Sep 15 '22 02:09 PureWeen

I have the same problem. CollectionView takes more than 4 to 6 minutes to load 200 (GParams.GVDiplayLoadLimit) items. Items are displayed on two rows. No images loaded. Below is my XAML and Code to load data into the CollectionView ItemsSource

<Grid Grid.Row="1" VerticalOptions="FillAndExpand">
                        <Frame x:Name="FrameLocations">
                            <!--<Label Text="Locations" />-->
                            <CollectionView BackgroundColor="LightSkyBlue"
                                            ItemTemplate="{StaticResource DataTemplateLOC}"
                                            ItemsSource="{Binding AllSitesDv}"
                                            SelectedItem="{Binding CurrentSiteDv}"
                                            Style="{StaticResource ColWithEV}" />
                        </Frame>
                        <Frame x:Name="FrameObservations">
                            <!--<Label Text="Observations" />-->
                            <CollectionView ItemTemplate="{StaticResource DatatemplateOBS}"
                                            ItemsSource="{Binding AllObservationsDv}"
                                            Style="{StaticResource ColWithEV}" />
                        </Frame>
                    </Grid>
 private async Task DisplaySites()
        {
            ObservableCollection AllSitesDv;
            Task var1 = Task.Run(() =>
            {
                AllSitesDv.Clear();
                if (AllSites.Count <= 0) { return; }          //handle zero records

                if (AllSites.Count < GParams.GVDiplayLoadLimit)
                {
                    for (int i = 0; i < AllSites.Count; i++)
                    {
                        AllSitesDv.Add(AllSites[i]);
                    }
                    return;
                }
                for (int i = 0; i < GParams.GVDiplayLoadLimit; i++)
                {
                    AllSitesDv.Add(AllSites[i]);
                }
            });
            await var1;
        }

andy-shindey avatar Sep 15 '22 06:09 andy-shindey

@PureWeen Is it possible to change VSL behavior back to being limited?... Or at least throw some error in such cases? I think there are at least 10 different issues logged here related to that.

Frankly, I feel like StackLayouts are very confusing in MAUI and mostly useless, as we have to use Grid in most cases (StackLayout was confusing as hell in XF as well, but for different reasons).

Dreamescaper avatar Sep 15 '22 09:09 Dreamescaper

@jonathanpeppers this hierarchy feels problematic

    <ScrollView>
        <VerticalStackLayout>
            <CollectionView 

@nacompllo I basically just removed the outer two layouts and the app looked the same to me.

The app starts in 822ms on a Pixel 5, that is a huge difference down from 16 seconds!

jonathanpeppers avatar Sep 15 '22 13:09 jonathanpeppers

Or at least throw some error in such cases?

@Dreamescaper are you aware of anything other frameworks do like this? WPF?

If you wrapped any "virtualizing" panel in a ScrollView, I'm pretty sure it would do the same thing in WPF...

Right now the only idea I can think of is if CollectionView logged a warning at the console, but that doesn't feel very visible -- no one would see it.

jonathanpeppers avatar Sep 15 '22 13:09 jonathanpeppers

@jonathanpeppers I'm not talking about ScrollView here, but about VerticalStackLayout. I haven't ever worked with WPF, but I did work with XF, where StackLayout didn't grow infinitely.

Dreamescaper avatar Sep 15 '22 13:09 Dreamescaper

Right I'm referring to WPF, because it is the OG XAML UI framework that has all the same concepts

jonathanpeppers avatar Sep 15 '22 14:09 jonathanpeppers

You do not need a StackLayout to reproduce the slow collectionview in my example above just a collectionview housed inside a popup page from MAUI Community Toolkit behaves the same as if it were housed in a Stacklayout even though there is none in XAML.

LennoxP90 avatar Sep 15 '22 14:09 LennoxP90

@jonathanpeppers At least this change should be properly documented. Multiple issues were closed as "not-a-bug" (e.g. #5442, #4115, #4107, I assume that this one will be closed as well), and in all of them it was mentioned that this changed should be documented. But I haven't found any mentions of that neither in StackLayout documentation, nor in XF migration guide.

Dreamescaper avatar Sep 15 '22 14:09 Dreamescaper

@PureWeen Is it possible to change VSL behavior back to being limited?... Or at least throw some error in such cases? I think there are at least 10 different issues logged here related to that.

Frankly, I feel like StackLayouts are very confusing in MAUI and mostly useless, as we have to use Grid in most cases (StackLayout was confusing as hell in XF as well, but for different reasons).

Is it only confusing because it grows infinitely? Or do you have a different use case.

StackLayout was confusing as hell in XF as well, but for different reasons

This is basically what we're wanting to fix inside .NET MAUI

At this point in MAUI, StackLayouts work in a much more deterministic way. The controls are all allowed to be the size they want to be and XF doesn't try to just guess which leads to StackLayout was confusing as hell in XF as well

If the user doesn't provide guidelines for how to size elements we can't guess what size those elements should be. That's why a Grid is recommended for cases like this.

I realize it's a pain moving from XF but the end result is more logical and more performant when you use the correct layouts for your scenario.

For example, you could put a CollectionView with 15 items in a VSL and it renders the whole thing which a user might want.

Or at least throw some error in such cases?

I could see a more helpful warning if a CollectionView grows to a given size.

PureWeen avatar Sep 15 '22 14:09 PureWeen

@PureWeen

Is it only confusing because it grows infinitely? Or do you have a different use case.

That is one use case, and yes - it is quite confusing. I wouldn't expect ScrollView, for instance, to be completely unusable inside of VSL. Second one is that VerticalOptions are ignored for VSL (and HorizontalOptions for HSL). I get that Expands were confusing, but personally I would expect that an item with HorizontalOptions="End" would be displayed, well, in the end.

I just feel that StackLayouts in MAUI are applicable for the simplest cases only, while in XF it was one of the most used controls. And if you think that is the proper way to go - ok, that's fine. But the lack of communication and documentation (apart from comments in github issues) regarding this change is, again, confusing.

For example, you could put a CollectionView with 15 items in a VSL and it renders the whole thing which a user might want.

I heavily doubt that, especially since the user won't even be able to scroll those 15 items in VSL.

Dreamescaper avatar Sep 15 '22 14:09 Dreamescaper

@LennoxP90 Does it help if you set HeightRequest explicitly for CollectionView to some value?

Dreamescaper avatar Sep 15 '22 15:09 Dreamescaper

I tried what you suggested and it worked, but I would like the collectionview take up the visual space it is housed in. I am guessing when it comes to a Popup page the height must be infinite even though the visual constraints do not extend past what is shown on screen

Below i have set the height request to 200 image image

the problem is that collectionview is shared between a full tab page and a popup page with different styling, so I didn't have to have duplicate code, and if i set the height on the popup page it will not be full height in the tab page which only shows the collectionview. I guess the simple solution is not share code

Btw it still is not super fast around a second to load instead of minutes, but this same code worked flawlessly in XF

LennoxP90 avatar Sep 15 '22 15:09 LennoxP90

@LennoxP90 how are you creating your popup page?

hartez avatar Sep 16 '22 15:09 hartez

 if( !bPopupShown )
          {
            //DL - 2022/09/09 - Setup PopupPage
            ContactsPopup = new ContactsPopupPage();
            ContactsPopup.Closed += ContactsPopup_Closed;
            ContactsPopup.Opened += ContactsPopup_Opened;
            //ContactsPopup.CanBeDismissedByTappingOutsideOfPopup = false;

            Shell.Current.CurrentPage.ShowPopup( ContactsPopup );
          }

LennoxP90 avatar Sep 16 '22 15:09 LennoxP90