I need to show a Loading modal in Blazor server, using Net6. When finish loading, it needs to change the text "loading..." with "finished".
But it only opens when everything is finished
I modified counter.razor from the example project so it takes 5 seconds of loading to Increment the counter:
@page "/counter"
<PageTitle>Counter</PageTitle>
<h1>Counter</h1>
<p role="status">Current count: @currentCount</p>
<button class="btn btn-primary" @onclick="IncrementCount">Click me</button>
<Modal @ref="modal">
<Title>This is a <em>Title!</em></Title>
<Body>
@if (loading)
{
<p>
Incrementing please wait...
</p>
}
else
{
<p>
Ready
</p>
}
</Body>
<Footer>
<button type="button" class="btn btn-secondary" data-dismiss="modal" @onclick="() => modal.Close()">Close</button>
</Footer>
</Modal>
@code {
private Modal modal;
private int currentCount = 0;
private bool loading;
private async void IncrementCount()
{
loading = true;
modal.Open();
StateHasChanged();
Task.Delay(5000).Wait();
currentCount++;
loading = false;
}
}
Modal.razor:
<div class="modal @modalClass" tabindex="-1" role="dialog" style="display:@modalDisplay; overflow-y: auto;">
<div class="modal-dialog modal-lg" role="document">
<div class="modal-content">
<div class="modal-header">
<h5 class="modal-title">@Title</h5>
<button type="button" class="close" data-dismiss="modal" aria-label="Close" @onclick="Close">
<span aria-hidden="true">×</span>
</button>
</div>
<div class="modal-body">
@Body
</div>
<div class="modal-footer">
@Footer
</div>
</div>
</div>
</div>
@if (showBackdrop)
{
<div class="modal-backdrop fade show"></div>
}
@code {
[Parameter]
public RenderFragment Title { get; set; }
[Parameter]
public RenderFragment Body { get; set; }
[Parameter]
public RenderFragment Footer { get; set; }
private string modalDisplay = "none;";
private string modalClass = "";
private bool showBackdrop = false;
public async void Open()
{
modalDisplay = "block;";
modalClass = "show";
showBackdrop = true;
}
public void Close()
{
modalDisplay = "none";
modalClass = "";
showBackdrop = false;
}
}
It only opens showing "Ready" AFTER the 5 seconds delay. I tried using another thread for opening the modal, using Task.Run, but it has the same result
Solved by Laurence Frost comment
Other workaround I found was this
private async void IncrementCount()
{
await Task.Run(()=>{
loading = true;
modal.Open();
InvokeAsync(StateHasChanged);
});
Task.Delay(2000).Wait();
currentCount++;
loading = false;
StateHasChanged();
}
One potential reason might be because you are using async void as opposed to async Task in your methods.
Try changing your IncrementCount method as follows:
private async Task IncrementCount()
{
loading = true;
modal.Open();
StateHasChanged();
await Task.Delay(5000);
currentCount++;
loading = false;
}
I would also change other async methods so that they return Task instead of void. You can read up on the specifics of why here: