Problem with Activity Indicator in Net Maui

808 Views Asked by At

I have an Activity Indicator control that I need to display when a button is pressed. This button gets one two to display on the screen. The problem is that the Activity Indicator is displayed after having completed the data collection process, not when it begins. My xaml code is:

<VerticalStackLayout>
        <ActivityIndicator x:Name="acIndicator"
                           IsVisible="False"
                           IsRunning="False"
                           Color="Red"/>
        <Button x:Name="btIndicatorOn"
                Text="Obtener Prevision"
                Clicked="btIndicatorOn_Clicked"/>
        <Grid>
            <Grid.RowDefinitions>
                <RowDefinition Height="*"/>
            </Grid.RowDefinitions>
            <Grid.ColumnDefinitions>
                <ColumnDefinition Width="*" />
                <ColumnDefinition Width="*" />
            </Grid.ColumnDefinitions>
            <mapas:Map x:Name="mapa"
                    IsVisible="false"
                    Grid.Row="0"
                    Grid.Column="0"/>  
            <ScrollView x:Name="scrollView"
                    Grid.Row="0"
                    Grid.Column="1"
                    VerticalOptions="FillAndExpand">
                <StackLayout>
                    <treeView:TreeView x:Name="tvPrevision">

                    </treeView:TreeView>
                </StackLayout>
            </ScrollView>
        </Grid>
    </VerticalStackLayout>

My C# code is :

void btIndicatorOn_Clicked(System.Object sender, System.EventArgs e)
    {
        acIndicator.IsVisible = true;
        acIndicator.IsRunning = true;
        // here I need to show the ActivityIndicator
        // mostrar mapa
        mapa.IsVisible = true;
        mapa.MoveToRegion(MapSpan.FromCenterAndRadius(new Location(41.21301, 1.73250), Distance.FromMiles(0.5)));
        string cadenaSituacion =  " 41.21º  N  1.73º  E" ;
        var pin = new Pin
        {
            Label = cadenaSituacion,
            Address = cadenaSituacion,
            Type = PinType.Place,
            Location = new Location(41.21301, 1.73250)
        };

        mapa.Pins.Add(pin);
        ObtenerPrevision();
    }
    
    public void ObtenerPrevision()
    {
        string url = string.Format("http://api.openweathermap.org/data/2.5/forecast?units=metric&lat={0}&lon={1}&lang=es&APPID={2}", viewModel.LatitudMapa, viewModel.LongitudMapa, OpenWeatherKey);
        WebClient web = new WebClient();

        var json = web.DownloadString(url);
        var Object = JsonConvert.DeserializeObject<weatherForecast>(json);
        weatherForecast forecast = Object;
        // Cargamos los datos en el tipo de dato definido
        List<list> filaMeteo = forecast.list;
        foreach (var item in filaMeteo)
        {
            DatosPrevision.Add(new TreeViewNode(item.dt_txt)
            {
                Children =
            {
                new TreeViewNode(item.weather[0].description),
                new TreeViewNode("Temperatura "+ String.Format("{0:N1}", item.main.temp) + " ºC"),
                new TreeViewNode("Dirección Viento "+ String.Format("{0:N1}", item.wind.deg) + " º"),
                new TreeViewNode("Velocidad Viento "+String.Format("{0:N1}", ((item.wind.speed * 3600) / 1852)) + " " + "Nudos"),
                new TreeViewNode("Presión atmosférica sobre el suelo "+item.main.grnd_level+ " hPa"),
                new TreeViewNode("Presión atmosférica sobre el mar "+item.main.sea_level+ " hPa"),
                new TreeViewNode("Humedad "+item.main.humidity+ "%"),
            }
            });

        }
        tvPrevision.ItemsSource = DatosPrevision;
        //acIndicator.IsVisible = false;
        //acIndicator.IsRunning = false;
    }

Any ideas to solve this problem? Thanks !!!

2

There are 2 best solutions below

0
On BEST ANSWER

It looks like you are missing async/await for the method ObtenerPrevision.

You could try something like this

public async void ObtenerPrevision()
{
    await Task.Delay(10000);
    acIndicator.IsVisible = false;
    acIndicator.IsRunning = false;
}
0
On

I would recommend to use a ViewModel with the MVVM toolkit and DataBinding. It would look similar to this and you would need to register your ViewModel and Page as a Service, as well as the HttpClient inside the MauiProgram CreateMauiApp() class:

    builder.Services.AddTransient<HttpClient>();
    builder.Services.AddTransient<YourPageViewModel>();
    builder.Services.AddTransient<YourPage>();


public abstract partial class BaseViewModel : ObservableObject
{
    public BaseViewModel()
    {
    }

    [ObservableProperty]
    public bool isBusy = false;
}

public partial class YourPageViewModel : BaseViewModel
{
    private readonly HttpClient _httpClient;
    public YourPageViewModel(HttpClient httpClient)
    {
    }

    [RelayCommand]
    public async Task DownloadData()
    {
        IsBusy = true;
        try
        {
            var res = await _httpClient.GetAsync("http://api.openweathermap.org/data/2.5/forecast?units=metric&lat={0}&lon={1}&lang=es&APPID={2}", viewModel.LatitudMapa, viewModel.LongitudMapa, OpenWeatherKey);
            res.EnsureSuccessStatusCode();

            var obj = await res.Content.ReadFromJsonAsync<weatherForecast>().ConfigureAwait(true);
            // rest of your handling
        }
        finally
        {
             IsBusy = false;
        }

    }
}

in YourPage constructor:

    public YourPage(YourPageViewModel vm) 
    {
        InitializeComponent();
        //_vm = vm;
        this.BindingContext = vm;
    }
    //internal YourPageViewModel _vm; // if you need it here too

you can then bind the Command, which is created by '[RelayCommand]' and bind it to your button like this:

    <Button x:Name="btIndicatorOn"
            Text="Obtener Prevision" Command="{Binding DownloadDataCommand}"/>

    <ActivityIndicator x:Name="acIndicator"
                       IsVisible="{Binding IsBusy}"
                       IsRunning="{Binding IsBusy}"
                       Color="Red"/>

to get intellisense and better performance, also set the viewmodel as your datatype in the page xaml file like so:

<Page ....
           xmlns:viewmodels="clr-namespace:{YOURNAMESPACE}.ViewModels"
           x:DataType="viewmodels:YourPageViewModel" >

you could also populate your TreeViewNodes via DataBindings like so:

[ObservableProperty]
ObservableCollection<TreeViewNode> treeViews;

and then use data binding in your xaml page with ItemsSource="{Binding TreeViews}"