在 Blazor 中显示计时器

use*_*480 6 c# asp.net f# blazor-server-side asp.net-core-3.0

我正在尝试在服务器端 Blazor 应用程序中显示倒数计时器。我的代码在 F# 和 C# 中。该代码有些工作,但计时器永远不会按预期停止,并且计时器显示偶尔不会呈现所有数字。这是我第一次尝试 Blazor 服务器端应用程序。我不确定问题是异步问题、计时器问题还是渲染问题。

这是我的代码:

F#

let private setTimer countDown timeEvent =

    let timer = new Timer(float countDown * float 1000)
    let mutable time = 0

    time <- countDown

    timer.Elapsed.Add(fun arg ->
        time <- time - 1
        if time = 0
        then 
            timer.Stop()
            timer.Dispose()
        else
            ()
        timeEvent arg
    )

    timer.AutoReset <- true
    timer.Start()

let setTimerAsync countDown timeEvent = async{
    setTimer countDown timeEvent
    do! Async.Sleep (countDown * 1000)
}

type Timer (countDown) =

    member val CountDown : int = countDown with get,set

    member this.SetTimeAsTask (timeEvent) =
        setTimerAsync countDown timeEvent |> Async.StartAsTask
Run Code Online (Sandbox Code Playgroud)

C# / Blazor

@page "/CountDown"
@using System.Timers
@using ClientTImer
@using Microsoft.FSharp.Core

<h3>Count Down</h3>
<p>
    Task: @task <br />
    Status: @status
</p>
<p>
    Timer: @time
</p>

@code {
    string task = "";
    string status = "";
    int time = 5;

    protected override async Task OnInitializedAsync()
    {

        // Initial task and status
        task = "First Task";
        status = "Status One";

        Action<System.Timers.ElapsedEventArgs> timeEvent =
            t =>
            {
                UpdateTime().Wait();
            };

        var func = FuncConvert.ToFSharpFunc(timeEvent);

        await new ClientTImer.Timer(time).SetTimeAsTask(func);

        // Update task and status
        task = "Second Task";
        status = "Status Two";
        await new ClientTImer.Timer(time).SetTimeAsTask(func);

        // Update task and status
        task = "Third Task";
        status = "Status Three";

    }

    public async Task UpdateTime()
    {
        await InvokeAsync(() =>
        {
            time--;
            StateHasChanged();
        });
    }

}
Run Code Online (Sandbox Code Playgroud)

use*_*480 1

rmunn 让我走上了正轨,但我的逻辑有点偏离,因为我没有完全理解计时器类实际上在做什么。我不仅必须考虑开始时间,还必须考虑间隔,以使所有内容同步,并且代码现在按预期工作。这是更新后的代码:

F#:

let private setTimer countDownSec intervalSec timeEvent =

    let timer = new Timer(float intervalSec * float 1000)
    let mutable time = 0

    time <- countDownSec

    timer.Elapsed.Add(fun arg ->
        time <- time - 1
        if time <= 0
        then 
            timer.Stop()
            timer.Dispose()
        else
            ()
        timeEvent arg
    )

    timer.AutoReset <- true
    timer.Start()

let internal setTimerAsync countDownSec intervalSec timeEvent = async{
    setTimer countDownSec intervalSec timeEvent
    do! Async.Sleep (countDownSec * 1000)
}

type Timer (countDown) =

    member val CountDown : int = countDown with get,set

    member this.SetTimeAsTask (timeEvent, interval) =
        setTimerAsync countDown interval timeEvent |> Async.StartAsTask
Run Code Online (Sandbox Code Playgroud)

C#/Blazor:

@page "/CountDown"
@using System.Timers
@using ClientTImer
@using Microsoft.FSharp.Core
@using System.Threading

<h3>Count Down</h3>
<p>
    Task: @task <br />
    Status: @status
</p>
<p>
    Timer: @time
</p>

@code {
    string task = "";
    string status = "";
    int startCount = 5;
    int time;

    protected override async Task OnInitializedAsync()
    {
        time = startCount;

        // Initial task and status
        task = "First Task";
        status = "Status One";

        Action<System.Timers.ElapsedEventArgs> timeEvent =
            t =>
            {
                UpdateTime().Wait();
            };

        var func = FuncConvert.ToFSharpFunc(timeEvent);

        await new ClientTImer.Timer(startCount).SetTimeAsTask(func,1);

        // Update task and status
        task = "Second Task";
        status = "Status Two";
        await new ClientTImer.Timer(startCount).SetTimeAsTask(func,1);

        // Update task and status
        task = "Third Task";
        status = "Status Three";

    }

    public async Task UpdateTime()
    {
        await InvokeAsync(() =>
        {
            time--;

            if(time <= 0)
            {
                time = startCount;
            }

            StateHasChanged();
        });
    }

}
Run Code Online (Sandbox Code Playgroud)