Home > other >  Blazor-Server side UI Updating does not work or only partially
Blazor-Server side UI Updating does not work or only partially

Time:03-15

I have the following issue:

I have a frontend where certain Values are set by the Backend. The Values are saved in Lists and these List-Elements should be displayed at the frontend.

This works if at first load, at Refreshing the page manually etc... but not when using StateHasChanged() or ShouldRender()

While searching I found this article: Blazor Timer call async API task to update UI

So I was adding the Timer, and the Timer is indeed refreshing but only for like 30 seconds, afterwards it won't be refreshed anymore.

 <ul>
        @Time
 </ul>
System.Threading.Timer timer;
private string Time { get; set; }
protected override async Task OnInitializedAsync()
{
    _servers = DataCollection.srv;
    var timer = new System.Threading.Timer((_) =>
    {
        Time = DateTime.Now.ToString();
        InvokeAsync(() =>
        {
            StateHasChanged();
        });
    }, null, 0, 1000);
    base.OnInitialized();```

While the timer is refreshing all other elements will be refreshed too. But Refreshing the timer stops randomly, sometimes after 60s, sometimes after 2s. Clicking a button (which triggers a refresh by default) or anything won't start it again.

My question is: Why does it only work for a random amount of time?

Thanks for your time and sorry if this might be trivial

CodePudding user response:

<ul>
        @Time
        <button onclick="@Collect">Collect</button>
 </ul>

@code {
    System.Threading.Timer timer;
    private string Time { get; set; }
    protected override async Task OnInitializedAsync()
    {       
        var timer = new System.Threading.Timer((_) =>
        {
            Time = DateTime.Now.ToString();
            InvokeAsync(() =>
            {
                StateHasChanged();
            });
        }, null, 0, 1000);
        base.OnInitialized();
    }

    void Collect()
    {
        GC.Collect();            
    }
 }

Try above code on https://try.mudblazor.com/snippet. Since you are assigning Timer to a local variable in method scope , it is eventually garbage collected and your timer won't trigger anymore. You can simulate same using above example where I have introduced a button to trigger Garbage collection explicitly. Change in example to assign to timer variable instead of local var timer variable and try to trigger Garbage collection again and timer won't stop this time.

CodePudding user response:

Here's my test page based on your code. It uses Task.Delay to emulate your _servers = DataCollection.srv;. It doesn't freeze after 30-60 seconds.

That suggests there's a problem in _servers = DataCollection.srv;. Change out this line for the await Task./Delay(100) in your code and verify were the problem is.

@page "/"
<PageTitle>Index</PageTitle>

<div >
    @this.Time
</div>

@code {

    System.Threading.Timer? timer;

    private string Time { get; set; } = string.Empty;

    protected override async Task OnInitializedAsync()
    {
        // emulate a data get
        await Task.Delay(100);
        var timer = new System.Threading.Timer((_) =>
        {
            Time = DateTime.Now.ToString();
            InvokeAsync(() =>
            {
                StateHasChanged();
            });
        }, null, 0, 1000);
        await base.OnInitializedAsync();
    }
}

Also why are you calling base.OnInitialized(); from OnInitializedAsync()?

It's already been run: OnInitialized() is called by ComponentBase before OnInitializedAsync().

  • Related