I am developing a client using Uno Platform and WINUI3. I have small requirement to show the loader when some external API call is being made asynchronously for getting data. In fact i need this functionality across all pages.
i am using x:Bind to bind 'IsBusy' Observable Property of viewmodel (using CommunityToolkit.MVVM 8.0). when 'IsBusy' property set to 'true' in async InvokeCommand raised by button click, i am expecting it to start showing the loader in UI. and once my external API call is complete i set it back to 'false' so that loader will stop showing.
Unfortunately, this does not work as expected. what am i missing here? complete code is below.
MainPage.Xaml:
<Page
x:Class="TestMVVM.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="using:TestMVVM"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Background="{ThemeResource ApplicationPageBackgroundThemeBrush}">
<Page.Resources>
<local:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
</Page.Resources>
<Grid>
<!--<TextBlock Text="Hello, world!" Margin="20" FontSize="30" />-->
<ProgressRing Name="myLoader" Margin="0,0,5,0" Height="50" Width="50" IsActive="{x:Bind ViewModel.IsBusy}"/>
<TextBlock Name="txtLoader" FontWeight="SemiBold" FontSize="25" Text="Loading..." Visibility="{x:Bind ViewModel.IsBusy, Converter={StaticResource BoolToVisibilityConverter}}"/>
<Button Content="CLick me" Command="{x:Bind ViewModel.ItemInvokedCommand}"></Button>
</Grid>
</Page>
MainPage.Xaml.cs:
public sealed partial class MainPage : Page
{
public MainPageViewModel ViewModel { get; } = new MainPageViewModel();
public MainPage()
{
this.InitializeComponent();
//this.DataContext = ViewModel; // i tried to set like this as well but no luck
}
}
ViewModel:
public partial class MainPageViewModel : ObservableObject
{
private IAsyncRelayCommand _itemInvokedCommand;
public IAsyncRelayCommand ItemInvokedCommand => _itemInvokedCommand ?? (_itemInvokedCommand = new AsyncRelayCommand<TypedEventHandler<object, object>>(OnItemInvoked));
[ObservableProperty]
private bool isBusy;
private async Task OnItemInvoked(TypedEventHandler<object, object> args)
{
IsBusy = true;
//in real time i make some external API call here
await Task.Delay(TimeSpan.FromSeconds(10));
IsBusy = false;
}
}
You're missing Mode=OneWay
.
The default mode of x:Bind
is OneTime
(as opposed to the default mode of Binding
which is OneWay
).
Reference
<ProgressRing (...) IsActive="{x:Bind ViewModel.IsBusy, Mode=OneWay}"/>
<TextBlock (...) Visibility="{x:Bind ViewModel.IsBusy, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}"/>