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?
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
:
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>