.NET MAUI ActivityIndicator not showing or disappearing depending on binding value

1.3k views Asked by At

I want to display an ActivityIndicator while doing some http calls.

In my view model I have a property

public bool ShowActivityIndicator { get; set; } = false;

A button command

public void UploadSurveyCommand()
{
    ShowActivityIndicator = !ShowActivityIndicator; //TODO: change
}

In the Page

<Grid Padding="10">
    <ActivityIndicator x:Name="activity"
                       IsVisible="{Binding ShowActivityIndicator}"
                       IsRunning="True"
                       Color="{StaticResource NavigationBarColor}" ZIndex="1000"
                       VerticalOptions="Center" HorizontalOptions="Center"
                       WidthRequest="100" HeightRequest="100"/>
    <Button Text="{loc:Localize Upload}" 
            BackgroundColor="White" 
            TextColor="{StaticResource BtnColor}" 
            FontAttributes="Bold" 
            CornerRadius="30"
            WidthRequest="250"
            HeightRequest="50"
            Margin="0,15,0,0" 
            Command="{Binding UploadSurveyCommand}"/>
</Grid>

When I press the button, and the ShowActivityIndicator value changes to true the ActivityIndicator is not shown.

2

There are 2 answers

3
Wasyster On

I made a workaround:

In view model on the button event I added a WeakReferenceMessenger.

public async void UploadSurvey()
{
    WeakReferenceMessenger.Default.Send<ActivityIndicatorMessage>(new ActivityIndicatorMessage
          {
              IsActive = true
          });

    await Task.Delay(5000);

    WeakReferenceMessenger.Default.Send<ActivityIndicatorMessage>(new ActivityIndicatorMessage
          {
              IsActive = false
          });
}

Where the message class has one property

public class ActivityIndicatorMessage
{
    public bool IsActive { get; set; }
}

On the page code behind I register a WeekReferenceMessenger listener and registered it in the constructor.

private void SubScribeOnShowHideActivityIndicatorMessanger()
{
        WeakReferenceMessenger.Default.Register<ActivityIndicatorMessage>(this, (recepient, messaage) =>
        {
            
            activityIndicator.IsRunning = messaage.IsActive;
        });
}

Hope helps someone!

2
Julian On

Use RelayCommand's built-in IsRunning property

If you execute your HTTP requests inside an asynchronous method, let's just call it MakeHttpRequestAsync(), then you just need to change the method signature of your [RelayCommand] to async Task (don't use async void for commands or anywhere else unless you must, e.g. event handlers):

[RelayCommand]
public async Task UploadSurveyAsync()
{
    await MakeHttpRequestAsync();
}

And then you can bind to the generated Command's IsRunning property:

<ActivityIndicator x:Name="activity"
                   IsVisible="{Binding UploadSurveyCommand.IsRunning}"
                   IsRunning="{Binding UploadSurveyCommand.IsRunning}" />

The RelayCommand's IsRunning property gets set automatically while it's executing.

There's no need for the ShowActivityIndicator property if you're only using it in a single place.

Alternative: Make ShowActivityIndicator observable

However, if you want to use the ShowActivityIndicator property, then you'll need to make it observable.

Replace

public bool ShowActivityIndicator { get; set; }

with

[ObservableProperty]
private bool _showActivityIndicator;

Then you can still bind to ShowActivityIndicator, it's up to you.