Search code examples
mauimaui-community-toolkit

ActivityIndicator is not running in certain scenarios while using RelayCommand


I'm trying to implement RelayCommand's built-in IsRunning property as described by Julian, but for some reason the only scenario that works is when using the Save button Command.

Here is what I have tried so far:

XAML Structure

<Grid>
    <VerticalStackLayout Padding="20" Spacing="20" VerticalOptions="Fill">
        <Picker Title="Pick Book" 
            ItemsSource="{Binding Books}"
            SelectedItem="{Binding SelectedBook}"
            ItemDisplayBinding="{Binding BookName}">
        </Picker>

        <Picker Title="Pick Chapter"
            ItemsSource="{Binding Chapters}"
            SelectedItem="{Binding SelectedChapter}"
            ItemDisplayBinding="{Binding ChapterName}" />

        <Button Text="Save" 
            Command="{Binding SaveButtonCommand}" />
    </VerticalStackLayout>

    <ActivityIndicator x:Name="booksActivity"
      IsVisible="True"
      IsRunning="{Binding BooksServiceCommand.IsRunning}"/>

    <ActivityIndicator x:Name="chaptersActivity"
      IsVisible="True"
      IsRunning="{Binding ChaptersServiceCommand.IsRunning}"/>

    <ActivityIndicator x:Name="buttonActivity"
      IsVisible="True"
      IsRunning="{Binding SaveButtonCommand.IsRunning}"/>
</Grid>

ViewModel Structure

public partial class BooksViewModel : ObservableObject
{
    public class Book { public int BookId { get; set; } public string BookName { get; set; } }
    public class Chapter { public string ChapterName { get; set; } }

    [ObservableProperty]
    private Book _selectedBook;

    [ObservableProperty]
    Chapter _selectedChapter;

    [ObservableProperty]
    ObservableCollection<Book> _books;

    [ObservableProperty]
    ObservableCollection<Chapter> _chapters;

Calling BooksService from constructor doesn't trigger the ActivityIndicator ring

    public BooksViewModel()
    {
       Task.Run(() => BooksServiceAsync());
    }

    [RelayCommand]
    public async Task BooksServiceAsync()
    {
        // Run ActivityIndicator ring here
        await Task.Delay(TimeSpan.FromSeconds(5));
        Books = await Task.Run(() => FetchBooks());
    }

    private ObservableCollection<Book> FetchBooks()
    {
        return  [ 
            new Book { BookName = "Book1"}, 
            new Book { BookName = "Book2" }, 
            new Book { BookName = "Book3" }];
    }

OnSelectedBookChanged doesn't trigger the ActivityIndicator ring

    partial void OnSelectedBookChanged(Book value)
    {

        Task.Run(() => ChaptersServiceAsync(value.BookId));
    }

    [RelayCommand]
    public async Task ChaptersServiceAsync(int bookId)
    {
        // Run ActivityIndicator ring here
        await Task.Delay(TimeSpan.FromSeconds(5));
        Chapters = await Task.Run(() => FetchChapters());
    }

    private ObservableCollection<Chapter> FetchChapters()
    {
        return [
            new Chapter { ChapterName = "Chapter1"},
            new Chapter { ChapterName = "Chapter2" },
            new Chapter { ChapterName = "Chapter3" }];
    }

    

Button Scenario is working and successfully triggers the ActivityIndicator ring

    [RelayCommand]
    public async Task SaveButton()
    {
        // Run ActivityIndicator ring here
        await Task.Delay(TimeSpan.FromSeconds(5));
    }
}

What could have went wrong in here?


Solution

  • I'm trying to implement RelayCommand's built-in IsRunning property as described by Julian, but for some reason the only scenario that works is when using the Save button Command.

    I tested the code you provided and reproduced the question.

    The reason why BooksService and ChaptersServiceAsync do not trigger the ActivityIndicator ring is that you did not use BooksServiceCommand or ChaptersServiceAsyncCommand. When you type "BooksSer" in the constructor, the IDE's smart association will display BooksServiceCommand: enter image description here

    This also explains that Button Scenario is working and successfully triggers the ActivityIndicator ring.

    So, if you add a button to bind (use) BooksServiceCommand, it can trigger the ActivityIndicator ring.

    <VerticalStackLayout Padding="20" Spacing="20">
        <Picker Title="Pick Book"
        ItemsSource="{Binding Books}"
        SelectedItem="{Binding SelectedBook}"
        ItemDisplayBinding="{Binding BookName}">
        </Picker>
    
       <Picker Title="Pick Chapter"
        ItemsSource="{Binding Chapters}"
        SelectedItem="{Binding SelectedChapter}"
        ItemDisplayBinding="{Binding ChapterName}" />
    
       <Button Text="Save"
        Command="{Binding SaveButtonCommand}" />
    
        <Button Text="LoadBooks"
        Command="{Binding BooksServiceCommand}" />
    </VerticalStackLayout>