how to do a loading screen during an async await process in.net #18717
Replies: 7 comments
-
My approach to this has been the following: Using .NET MAUI Community Toolkit I have created a Popup with just an ActivityIndicator. Then just before the time consuming task I show the Popup and close it right after the the task has finished. In the last release of .NET MAUI Community Toolkit it includes a service you can register within your DI container but I haven't use it because makes it hard to close the Popup outside the Popup itself, like with an undetermined time task. |
Beta Was this translation helpful? Give feedback.
-
@tatoadsl Can you, please, provide an example? I guess your time consuming task is being executed on a background thread otherwise the ActivityIndicator will get freezed, am I correct? |
Beta Was this translation helpful? Give feedback.
-
Hi @mihaimyh It is kinda easy to make it work using a PopUp. Here is the call to the pop up and the long running task called once the popup has been shown:
I have created a PopupService to help show the popup. I haven't yet use the PopupService included in the .NET MAUI Community Toolkit that now allows to close the popup through the service.
and the Popup is defined like this:
It is working good for me, hope that the example is useful. |
Beta Was this translation helpful? Give feedback.
-
I have found the following library useful if you're app is mobile only: |
Beta Was this translation helpful? Give feedback.
-
So did you solve this ? If yes what solution did you choose ? |
Beta Was this translation helpful? Give feedback.
-
What we do is we use the Maui toolkit statecontainer - it’s like a skeleton- shimmering control that I see on many apps and websites - that is a way more modern way of handling loading than a standard circle progress animation- you can have many states loading - success - empty and you show the relative screen depending on the status - hope this triggers your curiosity to look into it . |
Beta Was this translation helpful? Give feedback.
-
If you have a lot of work to do, consider moving it to a non UI thread with Task.Run. The following simulates performing extensive work with regular 1-second updates to the UI thread. public MainPage()
{
InitializeComponent();
Task.Run(async () => await DoLotsOfWork());
}
async Task DoLotsOfWork()
{
await this.Dispatcher.DispatchAsync(() => IsBusy = true);
Stopwatch sw = new();
sw.Start();
int lotsOfIterations = 10000;
for (int i = 0; i < lotsOfIterations; i++)
{
// do a piece of work here
await Task.Delay(50);
// update user at 1-second intervals
if (sw.Elapsed >= TimeSpan.FromSeconds(1))
{
double progress = i * 100.0 / lotsOfIterations;
await this.Dispatcher.DispatchAsync(() => statusLabel.Text = $"Doing work {progress}%");
sw.Restart();
}
}
await this.Dispatcher.DispatchAsync(() => statusLabel.Text = $"All work done");
await this.Dispatcher.DispatchAsync(() => IsBusy = false);
} <ContentPage>
<Grid>
<!-- Insert your content here -->
<!-- Floating loading indicator with status text -->
<VerticalStackLayout HorizontalOptions="Center" VerticalOptions="Center" Spacing="10" IsVisible="{Binding IsBusy}">
<ActivityIndicator IsRunning="{Binding IsBusy}" />
<Label x:Name="statusLabel" HorizontalOptions="Center" />
</VerticalStackLayout>
</Grid>
</ContentPage> For populating large lists, consider using thread-safe producer-consumer patterns. The ConcurrentQueue can help you get started. public partial class MainPage : ContentPage
{
public ObservableCollection<string> LotsOfData { get; } = [];
ConcurrentQueue<string> largeQueue = new();
public MainPage()
{
BindingContext = this;
InitializeComponent();
Task.Run(() => ProduceLotsOfData());
Task.Run(async () => await ConsumeLotsOfData());
}
void ProduceLotsOfData()
{
for (int i = 0; i < 1000; i++)
{
var data = $"Item {i}";
largeQueue.Enqueue(data);
}
}
async Task ConsumeLotsOfData()
{
await this.Dispatcher.DispatchAsync(() => IsBusy = true);
Stopwatch sw = new();
sw.Start();
while (largeQueue.TryDequeue(out var data))
{
await this.Dispatcher.DispatchAsync(() => LotsOfData.Add(data));
if (sw.Elapsed >= TimeSpan.FromSeconds(1))
{
double progress = LotsOfData.Count * 100.0 / 1000;
await this.Dispatcher.DispatchAsync(() => statusLabel.Text = $"Populating data {progress}%");
sw.Restart();
}
}
await this.Dispatcher.DispatchAsync(() => IsBusy = false);
}
} <?xml version="1.0" encoding="utf-8" ?>
<ContentPage x:DataType="local:MainPage">
<Grid>
<!-- Example content here -->
<CollectionView ItemsLayout="VerticalGrid,10" ItemsSource="{Binding LotsOfData}">
<CollectionView.ItemTemplate>
<DataTemplate x:DataType="x:String">
<Grid Padding="10">
<Label Text="{Binding}" />
</Grid>
</DataTemplate>
</CollectionView.ItemTemplate>
</CollectionView>
<!-- Floating loading indicator with status text -->
<VerticalStackLayout
HorizontalOptions="Center"
IsVisible="{Binding IsBusy}"
Spacing="10"
VerticalOptions="Center">
<ActivityIndicator IsRunning="{Binding IsBusy}" />
<Label x:Name="statusLabel" HorizontalOptions="Center" />
</VerticalStackLayout>
</Grid>
</ContentPage> |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
-
Before everything forgive me for the bad english and the mistakes i'd could do in the code I'm just an student and I cannot find the solution to my problem, or I don't understand it, anywhere.
So, I have a Class, "ClienteService" where I load a List of Cliente.
namespace Pantalla_Cliente { class ClienteService { public async Task<List<Cliente>> GetClientesAsync() { string url = Program.rutaBase + Rutas.cliente; string response = await ApiClient.GetRequestAsync("GET", url, Program.token); List<Cliente> listClientes = JsonSerializer.Deserialize<List<Cliente>>(response); return listClientes; } } }
I have a form where I get the list and with the info I got I create "cards" with the info of the customer.
` private async void ObtenerClientes()
{
List listCliente = await clienteService.GetClientesAsync();
CrearPanelesClientes(listCliente);
}
The problem is that when I show the list, there's an small amount of time. less than 0.5s, so I want a loading screen for that time, because with 30 customers maybe is 0.2s, but if we get more customers, the time will increase.
I tried with a pictureBox making visible before " List listCliente = await clienteService.GetClientesAsync();" and after that making it invisible again. But it doesn't show the gif, the only way I can see the gif if I put a delay of 3s, but I dont want to put manually the time I want to wait
Beta Was this translation helpful? Give feedback.
All reactions