How to implement Activity/Wait Indicator in dotnet Maui?

9.1k Views Asked by At

I needed to implement a wait indicator for a page in my Maui app.

Searching gave me this, but no step by step instructions.

So how do I do this?

2

There are 2 best solutions below

0
balintn On BEST ANSWER

Overview:

  • The control to display the animation is called ActivityIndicator.
  • ActivityIndicator is a visual element, should be part of your page.
    So, add an ActivityIndicator to your xaml.
  • The state of the indicator is part of logic - should live in your view model.
    So, add a bindable property to your view model, and bind ActivityIndicator.IsRunning to this property.

Sample (I haven't tested, just for illustration)
Page (xaml):

<?xml version="1.0" encoding="utf-8" ?>
<ContentPage xmlns="http://schemas.microsoft.com/dotnet/2021/maui"
             xmlns:x="http://schemas.microsoft.com/winfx/2009/xaml"
             xmlns:customcontrols="clr-namespace:Waiter.Maui.CustomControls"
             x:Class="..." >

    <ContentPage.Content>
        <ActivityIndicator IsRunning="{Binding IsBusy}" />
        <Button Text="Go" Command="{Binding GoCommand}" />
    </ContentPage.Content>
</ContentPage>

ViewModel:

namespace MyNamespace
{
    public class MyViewModel : BaseViewModel
    {
        public MyViewModel()
        {
            GoCommand = new Command(execute: OnGo, canExecute: true);
        }

        public Command GoCommand { get; }
        private void OnGo()
        {
            MainThread.InvokeOnMainThreadAsync(async () =>
            {
                IsBusy = true;
                Thread.Sleep(5000);
                IsBusy = false;
                return result;
            });
        }
    }
}

BaseViewModel class (so that it can be re-used, from existing community content):

using System.ComponentModel;
using System.Runtime.CompilerServices;

namespace Waiter.Maui.Pages
{
    public class BaseViewModel : INotifyPropertyChanged
    {
        bool isBusy = false;
        public bool IsBusy
        {
            get { return isBusy; }
            set { SetProperty(ref isBusy, value); }
        }

        string title = string.Empty;
        public string Title
        {
            get { return title; }
            set { SetProperty(ref title, value); }
        }

        protected bool SetProperty<T>(ref T backingStore, T value,
            [CallerMemberName] string propertyName = "",
            Action onChanged = null)
        {
            if (EqualityComparer<T>.Default.Equals(backingStore, value))
                return false;

            backingStore = value;
            onChanged?.Invoke();
            OnPropertyChanged(propertyName);
            return true;
        }

        #region INotifyPropertyChanged
        public event PropertyChangedEventHandler PropertyChanged;
        protected void OnPropertyChanged([CallerMemberName] string propertyName = "")
        {
            var changed = PropertyChanged;
            if (changed == null)
                return;

            changed.Invoke(this, new PropertyChangedEventArgs(propertyName));
        }
        #endregion
    }
}
0
H.A.H. On

I want to point out few things.

First of all, this "IsBusy" that I see getting recommended all around, is working strategy. I can only recommend using CommunityToolkit.MVVM, and letting it do your job, and handle all notification code instead of you.

However, using such boolean variable, is no different than using Lock, Mutex, Semaphore, etc. A programmer has to be very careful how and when it is changed, otherwise all kinds of bugs may occur.

In reality, most problems can be solved with commanding itself. Specifically CanExecute property is more than enough.

I recommend this: https://learn.microsoft.com/en-us/dotnet/maui/fundamentals/data-binding/commanding?view=net-maui-7.0

Before becoming slave to manual changing bool variables.