Declined
Last Updated: 19 Jan 2024 17:37 by ADMIN
Kevin
Created on: 17 Jan 2024 21:54
Category: BusyIndicator
Type: Bug Report
0
RadBusyIndicator freezes during data binding

During data binding, the busy indicator freezes.  This is not a problem with the MAUI ActivityIndicator, however. See the attached video

I created a repo here to reproduce the issue: https://github.com/kklose23/busyindicator-freezing

Note:  I know there's ways to make the data binding in that repo more efficient.  I just wanted a good example.

6 comments
ADMIN
Lance | Senior Manager Technical Support
Posted on: 19 Jan 2024 17:37

Hello Kevin,

That part is interesting indeed, I suspect it has to do with the fact that the ActivityIndicator is a native android control not as subject to the .NET UI thread.

It might help to understand that the ActivityIndicator and the RadBusyIndicator are fundamentally different controls.

  • In .NET MAUI, it uses a Handler for the native Android element through the IActivityIndicator Interface. So you're getting the native busy/activity view.
  • whereas the Telerik UI for Maui BusyIndicator is a cross platform view, in the MAUI layer, using SkiaSharp to render its visuals. It also has an extra level of functionality in that it has support for two different internal views that get swapped out.

Here's a very rudimentary flowchart:

The advantage to one over the other comes down to preference. If you want the same consistency of appearance, color, and behavior across all the platforms, then the RadBusyIndicator is the choice. If you don't care about those things and ore okay with the  want the native platform's appearance, then the ActivityIndicator might be better.

 

As to your question on whether or not the RadBusyIndicator has to run the on the UI thread? It must, because .NET MAUI requires all UI elements to be executed on the UI thread. Even simply adding items to an ObservableCollection that is bound to the UI thread will still force marshalling to the main thread.

What you could to help mitigate UI thread interferences is to also do the item generation n a task and return those results to the UI thread when done.you can also use an ObservableRangeCollection instead of ObservableCollection so that you only need to perform a single AddRange operation (instead of 300 different/expensive Add operations).

For example:

  public ObservableRangeCollection<string> Items { get; set; }

  [RelayCommand]
  async Task ReloadAsync()
  {
    IsBusy = true;

    await Task.Delay(2000);

    var newItems = await GetDataAsync(300);

    Items.AddRange(newItems);

    IsBusy = false;
  }

  Task<IEnumerable<string>> GetDataAsync(int count)
  {
      var data = Enumerable.Range(0, count).Select(i => $"{i}");

      return Task.FromResult(data);
  }

 

If you would like to continue discussing this with the team, please open a Technical Support ticket (we're currently having this conversation int he public Feedback Portal, which is for folks to track Bug Reports and Feature requests). The same team that handles Feedback Portal items will also be assisting you in the Support Ticket, too.

Regards,
Lance | Manager Technical Support
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Kevin
Posted on: 19 Jan 2024 16:50

Hey Lance,

The problem identified isn't something we've done in our main project.  That was just a result of me throwing together an inefficient UI thread operation to reproduce the problem.

However, I was wondering if the RadBusyIndicator animation has to run on the UI thread?  Since the ActivityMonitor is able to keep animating during the item generation, I assume there must be a way to do it for the RadBusyIndicator as well.

ADMIN
Lance | Senior Manager Technical Support
Posted on: 19 Jan 2024 16:35

Hello Kevin,

Thank you for the GIF. It looks like the busy indicator is spinning just fine for the 2 seconds of Task.Delay... but then the UI thread is hanging when the app starts adding items to the CollectionView.

This is indicative that your code is hanging the UI thread. The only reason you notice it is because the RadBusyIndicator is using the UI thread to animate and stops spinning when the thread is hung processing something else.

Looking at the debug output, there is some heavy GC occurring

The item generation code itself looks waaaay too simple to be causing UI hangs, even with the other considerations (debugger, emulator, etc). 

Problem Identified

Telerik Support isn't equipped to assist you with deep dives into performance (it's out of scope), however I did take a trip around the project to see if something stood out

I revisited the MainPage UI layout and there is indeed a major problem there. You're using a StackLayout as a parent of a UI virtualized control. This is an issue that Microsoft strongly warns you about throughout their docs, here are just a couple


We also try to give advice to avoid it, but you will not find this in the RadBusyIndicator's documentation because it is not relevant to the control.

Let me just give you the "bottom line" so that you can avoid problems like this in the future... here are 2 easy rules to follow to avoid this problem in the future

  • Zero starting space problem: Never put a UI virtualized control (CollectionView, RadListView, TreeeView, DataGrid, etc). in
    • A VerticalStackLayout with vertical item rendering
    • A HorizontalStackLayout with horizontal item rendering
    • A Grid RowDefinition Height=Auto (this is functionally the same as a VerticalStackLayout)
  • Infinite space problem: Never put a UI virtualized control (CollectionView, RadListView, TreeeView, DataGrid, etc). in
    • A ScrollView. This will immediately render all items in the scrollview, no matter how small the viewport is.

Note: If you are stuck and must use a conflicting parent element, the only way to avoid the above issues is if you give the UI virtualized control hard boundaries (ex. set a HeightRequest="500").

Updated Code

To prove this outcome, I have updated your code so that  to the following and opened a Pull Request. see the updated MainPage.xaml for the changes. See Re 1637719 by LanceMcCarthy · Pull Request #1 · kklose23/busyindicator-freezing.

I also updated Telerik.UI.for.Maui to 6.6.0 while I was in there. It is not relevant to today's issue, you just get the following improvements => Telerik UI for .NET MAUI (v6.6.0) Release Notes.

Regards,
Lance | Manager Technical Support
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Kevin
Posted on: 19 Jan 2024 15:12

Hi Didi,

 

I downloaded the repo and tested it, but I'm still getting the same result.  See the attached gif.

ADMIN
Didi
Posted on: 19 Jan 2024 14:47

Hello Kevin,

When working with the busy indicator you do not have to add the UI components inside the busy content. We have a sample integration example here: https://docs.telerik.com/devtools/maui/controls/busyindicator/integrate-with-listview 

Here is the relevant code with the changes:

<ContentPage ...>
    <Grid>
        <VerticalStackLayout>
            <Button Text="Load"
                    Command="{Binding ReloadCommand}" />

            <CollectionView ItemsSource="{Binding Items}">
                <CollectionView.ItemTemplate>
                    <DataTemplate>
                        <Label Text="{Binding .}" />
                    </DataTemplate>
                </CollectionView.ItemTemplate>
            </CollectionView>
        </VerticalStackLayout>

        <!-- Instead, you can put the RadBusyIndicator on top of the contentTemplate 
             Also notice how we are also binding to the IsVisible property, this will prevent blocking input gestures -->
        <telerik:RadBusyIndicator IsBusy="{Binding IsBusy}"
                                  IsVisible="{Binding IsBusy}"
                                  AnimationType="Animation2"
                                  AnimationContentHeightRequest="100"
                                  AnimationContentWidthRequest="100"
                                  AnimationContentColor="Black"
                                  VerticalOptions="Center"
                                  HorizontalOptions="Center"
                                  BackgroundColor="#AAFFFFFF"
                                  x:Name="RadBusyIndicator" />
    </Grid>
</ContentPage>

My colleague Lance forked the repo and applied the changes: https://github.com/LanceMcCarthy/busyindicator-freezing 

Test this and let me know the results. 

Regards,
Didi
Progress Telerik

Love the Telerik and Kendo UI products and believe more people should try them? Invite a fellow developer to become a Progress customer and each of you can get a $50 Amazon gift voucher.

Kevin
Posted on: 17 Jan 2024 21:56
Attaching a gif for easier viewing
Attached Files: