In my blazor, I put:
@if (cat.IsMeowing)
{
<div>Cat is meowing!!!</div>
}
In my Cat class, I put this:
public bool IsMeowing {get; set;} = false;
public void Meow()
{
Task.Run(async () =>
{
await Task.Delay(3000); // Cat takes a deep breath
IsMeowing = true; // MEOW!!!!!!!
});
}
The behaviour I want is that when I call Meow, there is a delay, and then it sets the variable which causes the Div to appear. However, blazor does not seem to notice that the variable has updated when it is updated via a closure from another thread.
If I remove the task, and just put the delay and the IsMeowing=true, then blazor notices it and updates correctly.
Is there a way I can get around this without implementing a callback?
Ultimately, I want to create a class that when a method is invoked on it, sets a variable after 3 seconds that blazor notices. Imagine for example that I want to show a message "This operation is taking a while..." if 3 seconds elapses while I'm doing other intensive work, so I can set one of these going, start doing my intensive work, and after my intensive work is done cancel it. If the intensive work took <3 seconds nothing would happen, and if it took more than 3 seconds the message would appear via the blazor if.
The task you create is something external, hence this applies. This is one of the cases when StateHasChanged() must be called. To do that:
Main.razor:
@implements IDisposable
@if (cat.IsMeowing)
{
<div>Cat is meowing!!!</div>
}
<button @onclick="() => cat.Meow()" title="Poke the cat">Poke the cat</button>
@code {
public Feline cat = new Feline();
protected override void OnInitialized()
{
cat.UpdateState += UpdateState;
}
public void Dispose()
{
cat.UpdateState -= UpdateState;
}
private void UpdateState()
{
InvokeAsync(StateHasChanged);
}
}
Feline.cs:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
public class Feline
{
public Action UpdateState = null;
public bool IsMeowing {get; set;} = false;
public void Meow()
{
Task.Run(async () =>
{
await Task.Delay(3000); // Cat takes a deep breath
IsMeowing = true; // MEOW!!!!!!!
if(UpdateState != null)
UpdateState();
});
}
}
Example: https://blazorrepl.telerik.com/cHOGmxPu44pZTDEm38
Correct me if I am wrong.
Blazor does not 'detect variable change' at all.
But you can easily use the async rendering logic:
//public void Meow()
public Task Meow()
{
Task t1 = ShowMeow();
Task t2 = longRunningTask(); // or t2 = Task.Run(longRunningTask)
await Task.WhenAll(t1, t2);
}
private Task ShowMeow()
{
await Task.Delay(3000); // Cat takes a deep breath
IsMeowing = true; // MEOW!!!!!!!
}
When longRunningTask() executes (mostly) synchronous then use Task.Run(), on Blazor-server only.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With