This is a migrated thread and some comments may be shown as answers.

Xamarin UWP RadListView Performance Bad

8 Answers 59 Views
ListView
This is a migrated thread and some comments may be shown as answers.
G
Top achievements
Rank 1
G asked on 24 Jul 2020, 09:36 PM

Resizing the window on our UWP app or simply navigating to the page with the Telerik RadListView on UWP hangs the app. Scrolling performance is bad too.  I have removed everything on this page and the only thing that continues to cause the poor performance the Telerik RadListView. We really only are binding to text, additionally I removed the Vector Image at the end of the row just in case that was an issue. I even removed the contents of the ListViewTemplateCell.View in case the issue was what we had for our template. The poor performance probably starts with items ranging from 200-300 items in the list. Performance for 900 items is absolutely terrible. Please help, we're looking to ship soon and don't want our customers having a terrible experience. 

Here is what we have:

<!--  List  -->
        <Grid VerticalOptions="FillAndExpand">
            <ScrollView Margin="{Binding SideSoftNavigationAdjustment}" VerticalOptions="FillAndExpand">
                <telerikDataControls:RadListView
                    x:Name="ItemsList"
                    Margin="20,0,0,0"
                    BackgroundColor="Transparent"
                    ItemTapped="ItemsList_OnItemTapped"
                    ItemsSource="{Binding ItemsListViewModel.Items}"
                    SelectionMode="Single"
                    VerticalOptions="FillAndExpand">
                    <telerikDataControls:RadListView.ItemTemplate>
                        <DataTemplate>
                            <telerikListView:ListViewTemplateCell>
                                <telerikListView:ListViewTemplateCell.View>
                                    <!--  need to use a grid as Telerik RadListView was having a problem with stack layout orientation horizontal  -->
                                    <Grid
                                        ColumnSpacing="0"
                                        HeightRequest="55"
                                        RowSpacing="0">
                                        <Grid.ColumnDefinitions>
                                            <ColumnDefinition Width="{Binding SelectAllWidth}" />
                                            <ColumnDefinition Width="*" />
                                            <ColumnDefinition Width="Auto" />
                                        </Grid.ColumnDefinitions>
                                        <mynamespace:VectorImage
                                            Grid.Column="0"
                                            HeightRequest="22"
                                            HorizontalOptions="Start"
                                            IsVisible="{Binding ShowSelectButton}"
                                            SvgPath="{Binding CheckedImageState}"
                                            VerticalOptions="CenterAndExpand"
                                            WidthRequest="22" />
                                        <StackLayout
                                            Grid.Column="1"
                                            Spacing="0"
                                            VerticalOptions="Center">
                                            <Label
                                                FontAttributes="Bold"
                                                FontSize="15"
                                                LineBreakMode="TailTruncation"
                                                Text="{Binding Name}"
                                                TextColor="{Binding ItemRowTextColor}"
                                                VerticalTextAlignment="End" />
                                            <Label
                                                FontSize="12"
                                                LineBreakMode="TailTruncation"
                                                Text="{Binding Subtitle}"
                                                TextColor="{Binding ItemRowTextColor}"
                                                VerticalTextAlignment="Start" />
                                        </StackLayout>
                                        <mynamespace:VectorImage
                                            Grid.Column="2"
                                            Margin="0,0,10,0"
                                            BackgroundColor="Transparent"
                                            HeightRequest="24"
                                            HorizontalOptions="End"
                                            IsVisible="{Binding ShowSelectButton, Converter={StaticResource InverseBoolConverter}}"
                                            SvgPath="{Binding EndIcon}"
                                            VerticalOptions="CenterAndExpand"
                                            WidthRequest="24">
                                            <mynamespace:VectorImage.GestureRecognizers>
                                                <TapGestureRecognizer Command="{Binding ItemRowOptionsCommand}" NumberOfTapsRequired="1" />
                                            </mynamespace:VectorImage.GestureRecognizers>
                                        </mynamespace:VectorImage>
                                    </Grid>
                                </telerikListView:ListViewTemplateCell.View>
                            </telerikListView:ListViewTemplateCell>
                        </DataTemplate>
                    </telerikDataControls:RadListView.ItemTemplate>
                    <telerikDataControls:RadListView.PressedItemStyle>
                        <telerikListView:ListViewItemStyle
                            BackgroundColor="{Binding ItemManagementViewModel.ItemListRowSelectionColor}"
                            BorderColor="{x:Static mynamespace:Colors.ItemListRowGreyLine}"
                            BorderLocation="Bottom"
                            BorderWidth="1" />
                    </telerikDataControls:RadListView.PressedItemStyle>
                    <telerikDataControls:RadListView.SelectedItemStyle>
                        <telerikListView:ListViewItemStyle
                            BackgroundColor="Transparent"
                            BorderColor="{x:Static mynamespace:Colors.ItemListRowGreyLine}"
                            BorderLocation="Bottom"
                            BorderWidth="1" />
                    </telerikDataControls:RadListView.SelectedItemStyle>
                    <telerikDataControls:RadListView.ItemStyle>
                        <telerikListView:ListViewItemStyle
                            BackgroundColor="Transparent"
                            BorderColor="{x:Static mynamespace:Colors.ItemListRowGreyLine}"
                            BorderLocation="Bottom"
                            BorderWidth="1" />
                    </telerikDataControls:RadListView.ItemStyle>
                </telerikDataControls:RadListView>
            </ScrollView>
            <telerikPrimitives:RadBusyIndicator
                x:Name="BusyIndicator"
                AnimationContentColor="{x:Static mynamespace:Colors.DarkMenuBlue}"
                AnimationType="Animation4"
                HeightRequest="150"
                HorizontalOptions="Center"
                IsBusy="{Binding ItemsManagementViewModel.IsRefreshing}"
                VerticalOptions="Start"
                WidthRequest="150" />
        </Grid>

 

 

8 Answers, 1 is accepted

Sort by
0
Lance | Manager Technical Support
Telerik team
answered on 24 Jul 2020, 10:49 PM

Hello Giancarlo,

To reason for the problem is that the layout you are using completely breaks UI virtualization. You are literally rendering all 300 items at once because it is expanding into the ScrollView until infinity (this is the purpose of a ScrollView)

Please remove the ScrollView and only use the Grid as the parent, you will see the performance improve drastically. 

To learn more, please go to the RadListView Getting Started documentation and scroll down to the Important Yellow Note:

Regards,
Lance | Manager - Technical Support
Progress Telerik

0
G
Top achievements
Rank 1
answered on 27 Jul 2020, 03:34 PM

Hi Lance,

Thanks for your prompt reply and referencing the docs. The reason the ScrollView was added was because scrolling did not work on the RadListView following resize. It looks like that isn't happening anymore following removing the ScrollView. The app performance is much better now for 1000 rows, however, manual horizontal resizing of the App window now doesn't work following removing the ScrollView. It looks like it tries but it gets stuck after a couple of pixels and doesn't resize to the desired horizontal size, so the performance is very bad there. We have also updated to the latest Telerik Nuget package 2020.2.624.1 (Telerik.UI.for.Xamarin and Telerik.UI.for.Xamarin.Primitives) but that did not help. I appreciate any help you can offer.

0
Lance | Manager Technical Support
Telerik team
answered on 27 Jul 2020, 05:39 PM

Hi G,

First, I should mention that you are using too many Telerik NuGet packages. You only need to use the single  Telerik.UI.for.Xamarin package (Primitives is already inside it).

About the resizing issue; without a runnable example to directly investigate, I am unable to provide you with any specific guidance. What I can say is that with normal Xamarin.Forms controls, I do not see any issues with cell resizing layout passes.

Therefore, if I had to guess, I would initially look at the custom vector rendering controls. If it is trying to redraw the image after every pixel change, then that can be hundreds of thousands of redraw attempts causing significant UI layer overhead.

For SVG, I recommend using FFImageLoading and use their SVG support, it's really good and handles UI drawing appropriately.

Further Assistance

If you continue to have trouble, instead of a public forum post please open a Priority Support ticket here and attach a runnable example so we can directly investigate the problem.

Tip - If you've never attached a project to a ticket before, be sure to delete the bin and obj folder from every project in the solution before zipping it up. This will drastically reduce the ZIP file size from hundreds of MBs down to just a few MBs.

Regards,
Lance | Manager - Technical Support
Progress Telerik

0
G
Top achievements
Rank 1
answered on 29 Jul 2020, 05:26 PM

Hi Lance,

We are using FFImageLoading and we have been pleased with it. I'll remove Primitives, thanks for letting me know.

I can open up a support ticket but I do have one last question which I wonder if this is a common issue you've seen. During debug in our UWP app we get a ton of these errors:

Binding: 'MyProperty' property not found on 'MyNamespace.MyViewModel', target property: 'MyNamespace.SvgPath'

... repeat times infinity :(

Then we get a whole bunch of these:

Exception thrown: 'System.ArgumentException' in System.Private.CoreLib.dll

... repeat times infinity

However, everything binds and works properly. Any thoughts on if this is part of our performance issue?

0
Lance | Manager Technical Support
Telerik team
answered on 29 Jul 2020, 06:24 PM

Hi G,

That error usually means a binding is incorrect. The names of the classes you just mentioned sound like it was copied from a code snippet.

Do you have a class like this, because it is what that error says should exist.

namespace MyNamespace
{
    public class MyViewModel
   {
        public something MyProperty { get;set;}
   }
}

Double check the BindingContext of the page, then the BindingContext in the DataTemplate (i.e. the actual item model that the ListView renders)

And yes, this would certainly cause a performance problem because Binding uses .NET Reflection. If it's happening thousands of times, this can really drag down the rendering time.

Regards,
Lance | Manager - Technical Support
Progress Telerik

0
G
Top achievements
Rank 1
answered on 29 Jul 2020, 09:01 PM
Is it the way we are binding in the example above? I'm a little concerned because looking at the documentation there is a simple view model with a parameterless constructor. The RadListView.BindingContext won't take an object that doesn't have a parameterless constructor. We have a ViewModel.ViewModel.Items and in each of those view models we have dependencies injected. Also, we populate the Items based on an event since we get the events from a remote endpoint which doesn't support pagination so when we do get data back it could be hundreds of rows. What is the recommended practice for this? Are we going to have to use LoadOnDemand to get around some of these issues? If so, does LoadOnDemand still allow the RadListView to leverage Virtualization?
0
Lance | Manager Technical Support
Telerik team
answered on 29 Jul 2020, 10:59 PM

Hi Giancarlo,

Yes, please open a ticket with a small demo with your setup. This will greatly increase the chances that we can fix everything in one response without having to take educated guesses. This will prevent any potential  multi-day delays in getting you a full solution :)

My team and I can help in more precise manner in the support ticket, but for now, let me answer your question at a high level.

BindingContext

I do find it a little odd that the ItemsSource is binding to something with the name of the view model type as opposed to an instance of that view model type.

For example, instead of

<Grid>
    <Label Text="{Binding MyViewModel.MyProperty}" />
<Grid>

It would normally be liek this

<Grid>
    <Grid.BindingContext>
        <vm:MyViewModel />
    </Grid.BindingContext>

    <Label Text="{Binding MyProperty}" />
</Grid>

The instance of the view model is set as the BindingContext of the element parent (or the element itself) and the viewmodel property is bound to the element's property.

Refactor Guess

As wild guess, here's what I imagine your page would normally look like if the inner area with the RadListView has a different BindingContext than the page does.

<Page>
    <Page.BindingContext>
        <!-- BindingContext for the page -->
        <viewmodels:ItemsManagementViewModel />
    </Page.BindingContext>
    
    <Grid Margin="{Binding SideSoftNavigationAdjustment}">
        <Grid>
              <Grid.BindingContext>
                  <!-- BindingContext for the ListView -->
                  <viewmodels:ItemsListViewModel />
              </Grid.BindingContext>
        
              <telerikDataControls:RadListView ItemsSource="{Binding Items}"/>
        </Grid>
        
        <telerikPrimitives:RadBusyIndicator IsBusy="{Binding IsRefreshing}"  />
    </Grid>
</Page>

Parameterless Requirement

To your question about requiring a parameter-less contractor, that is not true. It is up to you when and where you instantiate the ViewModel and set it as the BindingContext of the page/parent.

Whether or not the view model or item has a parameter constructor is ultimately irrelevant.

As a real world example, lets take a look at my CRM demo https://github.com/telerik/telerik-xamarin-forms-samples/tree/master/ArtGalleryCRM. The CustomerDetailsPage's constructor takes a parameter, which I instantiate the view model with:

The CustomerDetailsPage's BindingContext, CustomerDetaiViewModel is a view model class that takes a parameter of type Customer. (which was passed to it in the above snippet).

That view model has an ObservableCollection<Order> SelectedCustomerOrders that is the ItemsSource of the RadListView.

 

Finally in CustomerDetailPage.xaml,  you will see that the ItemsSource is bound to the collection 

and the DataTemplate is for every Order item:

 

Help With DataTemplate

As a tip to keep you on the right track when designing your DataTemplates, try setting the DataType for that template:

<DataTemplate x:DataType="models:MyItemClass">
    <!-- your content for every item in the list -->
<DataTemplate>

This has several advantages:

1. A compiled binding is much faster

2. IntelliSense will prevent you from binding to the wrong thing because it already knows what the BindingContext is

 

Blogs and Resources

If you're more curious about the CRM demo, I have written a 3 part blog series on how it was built.

Additionally, you will find a full setup walkthrough in the repo's readme. https://github.com/telerik/telerik-xamarin-forms-samples/blob/master/ArtGalleryCRM/readme.md 

 

Regards,
Lance | Manager - Technical Support
Progress Telerik

0
G
Top achievements
Rank 1
answered on 30 Jul 2020, 03:49 PM
Thanks for all your suggestions Lance. Unfortunately I tried the example and now am not getting any data in the RadListView. I'll open up a ticket and we can hopefully get to the bottom of this.
Tags
ListView
Asked by
G
Top achievements
Rank 1
Answers by
Lance | Manager Technical Support
Telerik team
G
Top achievements
Rank 1
Share this question
or