【问题标题】:change child value from parent on timer elapse在计时器经过时从父级更改子级值
【发布时间】:2022-01-01 14:10:16
【问题描述】:

我有一个简单的父子组件:

父母:

<div class="container-fluid">
    <div>
        <ChildComponent RandomNumber="@RandomNumberX" ></ChildComponent>
    </div>
</div>
@code {

public double RandomNumberX = 0.1;

private Timer timer = new Timer();

protected override void OnInitialized()
{
    timer.Interval = 3000;
    timer.Elapsed -= Set;
    timer.Elapsed += Set;
    timer.Start();
}

private void Set(object sender, ElapsedEventArgs e)
{
    var rng = new Random();

    var x = rng.Next(500, 600);
    RandomNumberX = x;
}}

孩子:

<svg height="100" width="100" style="position:absolute;  border-color: black; ">
    <g>
        <circle cx="50%" cy="25" r="5" stroke="red" stroke-width="2" fill="red" />
        <text x="50%" y="50" text-anchor="middle">@RandomNumber</text>
    </g>
</svg>
@code {
[Parameter]
public double RandomNumber { get; set; }

protected override void OnParametersSet()
{
        
}
}

在运行应用程序“RandomNumber”时显示 0.1,并且在父组件中不会更改,它会在计时器经过时更改。

【问题讨论】:

    标签: c# components blazor


    【解决方案1】:

    不久前我为一个 SVG 时钟制作了动画:

    注意:使用 dispose 以及我如何通过检查第二次更改将计算减少到仅在需要时。 Clock.razor

    <div class="d-flex flex-column align-items-center">
        <div class="time-sm">@timeZone.Id</div>
        <svg width="@Size" height="@Size" viewBox="0 0 1000 1000">
            <circle cx="@center" cy="@center" r="@radius" fill="@FaceColor" />
            <ClockHand Angle="hourAngle" Color="@HourColor" Width="50" Length="0.9" />
            <ClockHand Angle="minuteAngle" Color="@MinuteColor" Width="30" Length="0.95" />
            <ClockHand Angle="secondAngle" Color="@SecondColor" Width="20" Length="1" />
        </svg>
        <div class="time-sm">@currentSecond.DateTime.ToShortTimeString()</div>
        <div class="time-sm">@currentSecond.DateTime.ToString("dddd")</div>
    </div>
    

    Clock.razor.cs

    public partial class Clock : ComponentBase, IDisposable
    {
        internal const int radius = 500;
        internal const int size = 1000;
        internal const int center = size / 2;
        private double secondAngle = 0;
        private double minuteAngle = 0;
        private double hourAngle = 0;
        private TimeZoneInfo timeZone;
        private DateTimeOffset currentSecond;
        private readonly System.Timers.Timer timer = new();
    
        [Parameter]
        public int Size { get; set; } = 50;
    
        [Parameter]
        public string FaceColor { get; set; } = "#f5f5f5";
    
        [Parameter]
        public string HourColor { get; set; } = "blue";
    
        [Parameter]
        public string MinuteColor { get; set; } = "green";
    
        [Parameter]
        public string SecondColor { get; set; } = "red";
    
        [Parameter]
        public string TimeZone { get; set; }
    
        protected override void OnInitialized()
        {
    
            if (string.IsNullOrWhiteSpace(TimeZone) is true)
            {
                timeZone = TimeZoneInfo.Local;
            }
            else
            {
                timeZone = TimeZoneInfo.FindSystemTimeZoneById(TimeZone);
            }
    
            timer.Interval = 100;
            timer.Elapsed += Timer_Elapsed;
            UpdateClock();
            timer.Start();
        }
        public static DateTime GmtToPacific(DateTime dateTime)
        {
            return TimeZoneInfo.ConvertTimeFromUtc(dateTime,
                TimeZoneInfo.FindSystemTimeZoneById("Pacific Standard Time"));
        }
        private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
        {
            UpdateClock();
            InvokeAsync(StateHasChanged);
        }
    
        private void UpdateClock()
        {
            const double radiansPer60 = 360 / 60 * Math.PI / 180;
            const double radiansPer12 = 360 / 12 * Math.PI / 180;
    
            var currentTime = TimeZoneInfo.ConvertTime(DateTimeOffset.Now, timeZone);
            var roundedSencond = new DateTimeOffset(currentTime.Year, currentTime.Month, currentTime.Day, currentTime.Hour, currentTime.Minute, currentTime.Second, default);
    
            if (roundedSencond != currentSecond)
            {
    
                currentSecond = roundedSencond;
    
                var seconds = currentTime.Second;
                var minutes = currentTime.Minute;
                var hours = currentTime.Hour % 12;
    
                secondAngle = seconds * radiansPer60;
                minuteAngle = minutes * radiansPer60 + secondAngle / 60;
                hourAngle = hours * radiansPer12 + minuteAngle / 12;
            }
        }
    
        public void Dispose()
        {
            if (timer is not null)
            {
                timer.Dispose();
            }
        }
    }
    
    

    ClockHand.razor

    <line x1="500" y1="500" x2="@X" y2="@Y" style="stroke:@Color;stroke-width:@Width" />
    

    ClockHand.razor.cs

    public partial class ClockHand : ComponentBase
    {
        [Parameter]
        public double Angle { get; set; }
    
        [Parameter]
        public double Length { get; set; } = 1;
    
        [Parameter]
        public string Color { get; set; } = "black";
    
        [Parameter]
        public int Width { get; set; }
    
        double X => Math.Sin(Angle) * Clock.radius * Length + Clock.center;
        double Y => Math.Cos(Angle) * -Clock.radius * Length + Clock.center;
    }
    
    

    Useage

    <Clock TimeZone="Australia/Sydney" />
    

    <Clock />
    

    【讨论】:

      【解决方案2】:

      TimerElapsed 不是“正常”的 Blazor 生命周期事件。所以它不会自动触发重新渲染。 (例如 ButtonClick 事件)。

      所以你需要调用 StatehasChanged,并且为了满足它在另一个线程上的可能性,你需要 InvokeAsync。

      private async void Set(object sender, ElapsedEventArgs e)
      {
          var rng = new Random();
      
          var x = rng.Next(500, 600);
          RandomNumberX = x;
          await InvokeAsync(StatehasChnaged);
      }
      

      您通常应该避免使用async void,但这正是它的用途。

      旁注:初始化期间的timer.Elapsed -= Set; 只是解决方案的一半。

      在页面顶部使用@implements IDisposable 并添加

      public void Dispose()
      {
          timer.Elapsed -= Set;
      }
      

      【讨论】:

      • 感谢您的回复。这是工作。
      猜你喜欢
      • 2022-08-20
      • 2014-03-24
      • 1970-01-01
      • 1970-01-01
      • 2014-09-02
      • 1970-01-01
      • 1970-01-01
      • 2021-03-14
      • 2015-11-04
      相关资源
      最近更新 更多