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.
非同期メソッドを呼び出すには何をする必要がありますか?
本当にありがとう!
ベストアンサー1
おそらく GetValue() を Invoke() することは望ましくないでしょう。それはむしろ無意味です。タイマーは次のように実装できます。
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);
}
タイマーは破棄する必要があるため、タイマーを保存するためのフィールドを使用しました。Razor セクションに以下を追加します。
@implements IDisposable
コードにこれを追加します:
public void Dispose()
{
timer?.Dispose();
}