Blazor Server .NET 8 - UI not changing - Stack Overflow

admin2025-05-02  1

I have a really basic piece of code in Blazor Server .NET 8. I am not an expert on Blazor (yet), but more a backend developer in C# and .NET. My work allows me to learn Blazor and I can get far, but I can't seem to figure out how to update the UI, which seems pretty important.

I have seen this code a lot on my search of my problem:

@using System.Timers

@page "/testing"

Counter value is: @currentCount at @DateTime.UtcNow.ToString("HH:mm:ss")

@code{
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
        Console.WriteLine($"Count incremented: {currentCount}");
    }

    private Timer timer;

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            timer = new Timer();
            timer.Interval = 1000;
            timer.Elapsed += OnTimerInterval;
            timer.AutoReset = true;
            // Start the timer
            timer.Enabled = true;
        }
        base.OnAfterRender(firstRender);
    }

    private void OnTimerInterval(object sender, ElapsedEventArgs e)
    {
        IncrementCount();
        InvokeAsync(() => StateHasChanged());
    }

    public void Dispose()
    {
        // During prerender, this component is rendered without calling OnAfterRender and then immediately disposed
        // this mean timer will be null so we have to check for null or use the Null-conditional operator ?
        timer?.Dispose();
    }
}

Whatever I do, the UI is never updating the @currentCount value! The OnTimerInterval is hitting every second, so that works. But the InvokeAsync(() => StateHasChanged()); doesn't work. The StateHasChanged() (without the async) doesn't work either.

What I have tried:

  • ChatGPT (Not gong to do that again! Took me down the wrong path completely!)
  • Google (this code I have shown you is from different sources)
  • Trying to remove the async way, but that doesn't work either.

What am I doing wrong??

Update: StackOverflow gave a suggestion for another post:

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

This answer didn't work either.

I have a really basic piece of code in Blazor Server .NET 8. I am not an expert on Blazor (yet), but more a backend developer in C# and .NET. My work allows me to learn Blazor and I can get far, but I can't seem to figure out how to update the UI, which seems pretty important.

I have seen this code a lot on my search of my problem:

@using System.Timers

@page "/testing"

Counter value is: @currentCount at @DateTime.UtcNow.ToString("HH:mm:ss")

@code{
    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
        Console.WriteLine($"Count incremented: {currentCount}");
    }

    private Timer timer;

    protected override void OnAfterRender(bool firstRender)
    {
        if (firstRender)
        {
            timer = new Timer();
            timer.Interval = 1000;
            timer.Elapsed += OnTimerInterval;
            timer.AutoReset = true;
            // Start the timer
            timer.Enabled = true;
        }
        base.OnAfterRender(firstRender);
    }

    private void OnTimerInterval(object sender, ElapsedEventArgs e)
    {
        IncrementCount();
        InvokeAsync(() => StateHasChanged());
    }

    public void Dispose()
    {
        // During prerender, this component is rendered without calling OnAfterRender and then immediately disposed
        // this mean timer will be null so we have to check for null or use the Null-conditional operator ?
        timer?.Dispose();
    }
}

Whatever I do, the UI is never updating the @currentCount value! The OnTimerInterval is hitting every second, so that works. But the InvokeAsync(() => StateHasChanged()); doesn't work. The StateHasChanged() (without the async) doesn't work either.

What I have tried:

  • ChatGPT (Not gong to do that again! Took me down the wrong path completely!)
  • Google (this code I have shown you is from different sources)
  • Trying to remove the async way, but that doesn't work either.

What am I doing wrong??

Update: StackOverflow gave a suggestion for another post:

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

This answer didn't work either.

Share Improve this question edited Jan 2 at 12:50 Banana828 asked Jan 2 at 12:43 Banana828Banana828 796 bronze badges 6
  • 1 Just add: @rendermode InteractiveServer – D A Commented Jan 2 at 13:43
  • It is indeed most likely the rendermode. But I'm also missing an @implements IDisposable – Henk Holterman Commented Jan 2 at 13:51
  • @DA Do I add it to the beginning of the razor file, where the usings are located? – Banana828 Commented Jan 2 at 13:57
  • @HenkHolterman I have added the IDisposable and the Dispose() method, but nothing seems to change; still not visible – Banana828 Commented Jan 2 at 14:00
  • When you have the Dispose pattern correct and static rendering then the timer should be disposed immediately. Does it still tick? – Henk Holterman Commented Jan 2 at 14:15
 |  Show 1 more comment

2 Answers 2

Reset to default 0

If you deploy a Blazor Web App template solution with RenderMode: Server and Interactivity : Global, your code will work.

However, doing configuration stuff and mutating state in OnAfterRender{Async} is smelly code. See Blazor - should I read in my data in OnInitializedAsync() or OnAfterRenderAsync(true).

Here's a refactored version of your code:

@page "/"
@using System.Timers
@implements IDisposable

<PageTitle>Home</PageTitle>

<h1>Hello, world!</h1>

Counter value is: @currentCount at @DateTime.UtcNow.ToString("HH:mm:ss")

@code {
    [CascadingParameter] private HttpContext? httpContext { get; set; }

    private int currentCount = 0;

    private void IncrementCount()
    {
        currentCount++;
        Console.WriteLine($"Count incremented: {currentCount}");
    }

    protected override void OnInitialized()
    {
        // If static rendered, do not start the timer
        if (httpContext is not null)
            return;

        timer = new Timer();
        timer.Interval = 1000;
        timer.Elapsed += OnTimerInterval;
        timer.AutoReset = true;
        // Start the timer
        timer.Enabled = true;
    }

    private Timer? timer;

    private async void OnTimerInterval(object? sender, ElapsedEventArgs e)
    {
        IncrementCount();
        await InvokeAsync(StateHasChanged);
    }

    public void Dispose()
    {
        timer?.Dispose();
    }
}

Note that in Net9, you can simply do this to detect the RenderMode.

if (RendererInfo.IsInteractive)

Template Options:

Note: Interactivity Location:

I'm also not an expert but what I can see there is missing [parameter] by declaration of variable currentCount. It should be [parameter] private int currentCount = 0;

转载请注明原文地址:http://www.anycun.com/QandA/1746119396a91936.html