Search code examples
razorblazormaui

Blazor OnParametersSet is not called after parameter value is being updated


I think I must have missed something here... I thought OnParametersSet would be called if I assign a new value to a parameter but it seems it's not the case. I'm trying to make a component re-render each time I assign it a new value to one of it's parameter.

For example, the below is page conatining "Clock" component. Every second, I update the parameter value.

@code {

    public TimeSpan Duration { get; set; }
    public Timer Updater { get; set; }

    protected override void OnInitialized()
    {
        base.OnInitialized();
        this.Duration = TimeSpan.FromMinutes(60);

        this.Updater = new System.Timers.Timer(1000);
        Updater.Elapsed += OnTimerElapsed;
        Updater.Enabled = true;
    }

    private void OnTimerElapsed(Object source, ElapsedEventArgs eventArgs)
    {
        this.Duration = this.Duration.Add(TimeSpan.FromSeconds(-1));
        Debug.WriteLine($"New Duration is {this.Duration.ToString()}");
    }
}

<Clock Value="@this.Duration" />

The below is the clock razor component.

@code {
    [Parameter]
    public TimeSpan Value { get; set; }
}

<div class="clock">
    <div class="minutes">@this.Value.Minutes</div>
    <div class="min-sec-separator">:</div>
    <div class="seconds">@this.Value.Seconds</div>
</div>

It will be really appreciated if someone could point me out what I am missing here.

Give the value is TimeSpan, I expected this should just work without any intervention.


Solution

  • Try(parent):

    @using System.Timers
    
    @code {
    
        public TimeSpan Duration { get; set; }
        public Timer Updater { get; set; }
    
        protected override void OnInitialized()
        {
            this.Duration = TimeSpan.FromMinutes(60);
    
            this.Updater = new System.Timers.Timer(1000);
            Updater.Elapsed += OnTimerElapsed;
            Updater.Enabled = true;
            base.OnInitialized();
    
        }
    
        private void OnTimerElapsed(Object source, ElapsedEventArgs eventArgs)
        {
            this.Duration = this.Duration.Add(TimeSpan.FromSeconds(-1));
            StateHasChanged();
            Console.WriteLine($"New Duration is {this.Duration.ToString()}");
        }
    }
    
    <Clock Value="@this.Duration" />
    

    And the Clock.razor(child):

    @code {
        [Parameter]
        public TimeSpan Value { get; set; }
    }
    
    <div class="clock">
        <div class="minutes">@this.Value.Minutes</div>
        <div class="min-sec-separator">:</div>
        <div class="seconds">@this.Value.Seconds</div>
    </div>
    

    https://blazorrepl.telerik.com/mmFmbRvB17tQXjRy37

    For explanation please see @MrCakaShaunCurtis answer.