【问题标题】:Blazor Timer call async API task to update UIBlazor Timer 调用异步 API 任务来更新 UI
【发布时间】:2020-11-13 12:32:19
【问题描述】:

我正在 Blazor 服务器端页面中设置计时器。目标是每 x 秒调用一次 API,并根据返回值更新 UI。

我得到了这个代码:

private string Time { get; set; }

protected override void OnInitialized()
{
    var timer = new System.Threading.Timer((_) =>
    {
        Time = DateTime.Now.ToString();
        InvokeAsync(() =>
        {
            StateHasChanged();
        });
    }, null, 0, 1000);
    base.OnInitialized();
}

这很好用。 UI 每秒都会使用新的时间值进行更新。但是,我不知道如何调用异步任务来获取值。我想换行:

Time = DateTime.Now.ToString();

用一行调用以下函数:

private async Task<string> GetValue()
{
    var result = await _api.GetAsync<StringDto>("/api/GetValue");
    return result.Text;
}

我试过这条线:

Time = GetValue().Result;

但我收到以下错误:

The current thread is not associated with the Dispatcher. Use InvokeAsync() to switch execution to the Dispatcher when triggering rendering or component state.

调用异步方法需要做什么?

非常感谢!

【问题讨论】:

    标签: blazor blazor-server-side


    【解决方案1】:

    您可能不想 Invoke() GetValue(),那将毫无意义。您可以像这样实现计时器:

    System.Threading.Timer timer;
    protected override void OnInitialized()
    {
        timer = new System.Threading.Timer(async _ =>  // async void
        {
            Time = await GetValue();
            // we need StateHasChanged() because this is an async void handler
            // we need to Invoke it because we could be on the wrong Thread          
            await InvokeAsync(StateHasChanged);
        }, null, 0, 1000);
    }
    

    我使用了一个字段来存储 Timer,因为您应该将其处理掉,将其添加到 Razor 部分:

    @implements IDisposable
    

    这是代码:

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

    【讨论】:

    • 我喜欢您回答中的通用解决方案,但您是否打算省略对 base.OnInitialized() 的调用?
    • 是的,在普通页面中不需要。你可以把它放在“一般原则”之外,这是一个品味问题。查看 WeatherForecast 页面以获取参考。
    • 是的,我可以确认,如果您检查source.dot.net/#Microsoft.AspNetCore.Components/…,您会看到OnInitialized 中没有任何语句。
    【解决方案2】:

    试试这个代码:

      private string Time { get; set; }
    
    protected override void OnInitialized()
    {
        base.OnInitialized();
        var timer = new System.Threading.Timer((_) =>
        {
    
            InvokeAsync( async ()  =>
            {
                Time = await GetValue();
                StateHasChanged();
            });
        }, null, 0, 1000);
    
    }
    

    您的 GetValue 方法应该是:

    private async Task<string> GetValue()
    {
        return await _api.GetAsync<StringDto>("/api/GetValue");
      
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-07-07
      相关资源
      最近更新 更多