Search code examples
c#xamlmaui

Proper way of loading data with indicator


I would like to show activity indicator while the data is loading. What is the proper way?

When I navigate to this page the loading indicator is not shown at all, during the navigation feels like a little lag such as the loading happens when navigating.

View and ViewModel are registered as transient.

In the ViewModel:

[ObservableProperty]
bool _isBusy;

[ObservableProperty]
string _loadingText;

public ObservableRangeCollection<TestModel> Items { get; set; } = new ObservableRangeCollection<TestModel>();

public TestViewModel(IRepository repository)
{
    _repository = repository;
    LoadData();
}

private void LoadData() 
{
    Items.Clear();

    Task.Run(async () =>
    {
        try
        {
            await MainThread.InvokeOnMainThreadAsync(() =>
            {
               IsBusy = true;
               LoadingText = "Loading...";
            });
            _allItems = await _repository.GetAllAsync();
            Items.AddRange(_allItems );
        }
        catch (Exception)
        {

            throw;
        }
        finally 
        {
            await MainThread.InvokeOnMainThreadAsync(() =>
            {
                IsBusy = false;
            });
        }
    });
}

In the View:

<CollectionView
    IsVisible="{Binding IsBusy, Converter={StaticResource InvertedBoolConverter}}"
    ItemsSource="{Binding Items}"
    SelectionMode="None">
    <CollectionView.ItemTemplate>
        <DataTemplate>
            <Label Text="{Binding Name)"/>
        </DataTemplate>
    </CollectionView.ItemTemplate>
</CollectionView>

<VerticalStackLayout IsVisible="{Binding IsBusy}"
    HorizontalOptions="Center"
    Spacing="6"
    VerticalOptions="Center">
    <ActivityIndicator
        HeightRequest="44"
        HorizontalOptions="Center"
        IsRunning="{Binding IsBusy}"
        Scale="{OnPlatform iOS=1.3,
                           Android=1.0}"
        WidthRequest="44"
        Color="{DynamicResource PrimaryColor}" />

    <Label
        FontSize="14"
        HorizontalOptions="Center"
        HorizontalTextAlignment="Center"
        LineBreakMode="WordWrap"
        Text="{Binding LoadingText}"
        TextColor="{DynamicResource PrimaryColor}" />
</VerticalStackLayout>

Solution

  • Since you have defined the following variable, but you used variable IsBusyin .xaml.

    [ObservableProperty]
    bool _isBudy;
    

    So,please try to change the defined variable as follows:

    [ObservableProperty]
    bool _isBusy;
    

    And based on your code, I added some fake data to simulate this problem. But all work properly on my side.

    Please refer to the following code:

        private void LoadData()
        {
            Items.Clear();
    
            Task.Run(async () =>
            {
                try
                {
                    await MainThread.InvokeOnMainThreadAsync(() =>
                    {
                        IsBusy = true;
                        LoadingText = "Loading...";
                    });
                    //_allItems = await _repository.GetAllAsync();
                    // Items.AddRange(_allItems);
    
                   //add Task.delay
                    await Task.Delay(TimeSpan.FromSeconds(2));
    
                   // add some fake data here
                    AddItems();
                }
                catch (Exception)
                {
    
                    throw;
                }
                finally
                {
                    await MainThread.InvokeOnMainThreadAsync(() =>
                    {
                        IsBusy = false;
                    });
                }
            });
        }