Reputation: 117
When the user press on a specific button i need to show an animation inside the button and disable it ( the method called need several seconds to accompish). This is my html:
<div class="row">
<div class="col-lg-4">
@if (IsDownloading)
{
<button class="btn btn-primary float-right search disabled" disabled><span class='fa-left fas fa-sync-alt spinning'></span>Downloading...</button>
}
else
{
<button id="REC_PDF" class="btn btn-primary" @onclick="@(()=>getPDF())">Download Labels</button>
}
</div>
</div>
and this is my code:
protected bool IsDownloading { get; set; }
public async Task getPDF()
{
IsDownloading = true;
StateHasChanged();
await generate_pdf(labels);
IsDownloading = false;
StateHasChanged();
}
private async Task generate_pdf(List<Tuple<string, string, string, string>> filtered_label)
{
loading = true;
string PDF_PATH = "./PDF/" + CurrentValue;
foreach (Tuple<string,string,string,string> label in filtered_label)
{
if (!Directory.Exists(PDF_PATH))
{
Directory.CreateDirectory(PDF_PATH);
}
.......
The code is working but the rendering of the page called by StateHasChanged(); is executed 2 times when the method getPDF ( and generate_PDF consequentially) is fully executed.
I need page rendering on the frist call to show css loading animation.
( as suggested in other post i have used InvokeAsync(() => StateHasChanged()); but is not working)
Thanks.
Upvotes: 5
Views: 1924
Reputation: 30450
The click event is handled like this in Blazor:
var task = InvokeAsync(EventMethod);
StateHasChanged();
if (!task.IsCompleted)
{
await task;
StateHasChanged();
}
Note StateHasChanged
doesn't actually re-render the component, it just stacks a RenderFragment
delegate on the Render queue.
All the code runs on the UI Synchronisation context, so the render event queued by calling StateHasChanged
only gets executed either:
I can't see any code that yields in your generate_pdf
.
Try the following:
public async Task getPDF()
{
IsDownloading = true;
await Task.Yield();
await generate_pdf(labels);
IsDownloading = false;
}
Note: Directory.CreateDirectory
is not an async method. Only FileStream
has async methods.
Upvotes: 8
Reputation: 273824
The problem is that generate_pdf()
is not asynchronous. Adding async
is not enough. You need something asynchronous to enable a Render.
Since this is a UI problem I suggest to solve it in the top layer:
public async Task getPDF()
{
IsDownloading = true;
//StateHasChanged(); // not needed at start
await task.Delay(1); // allow the UI to update
try
{
await generate_pdf(labels);
}
finally
{
IsDownloading = false;
}
//StateHasChanged(); // not needed at the end
}
When generate_pdf() does not do any await
itself you might as well make it a normal void method.
Upvotes: 1
Reputation: 2800
Try this modifications:
public async Task getPDF()
{
if (IsDownloading) return;
IsDownloading = true;
StateHasChanged();
await generate_pdf(labels);
}
then at the end of generate_pdf
(better inside a try/finally block) add:
IsDownloading = false;
StateHasChanged();
Upvotes: 0