从内部调用异步方法 NavigationManager.LocationChanged
Calling async method from inside NavigationManager.LocationChanged
我正在使用 NavigationManager.LocationChanged
来捕获查询字符串。获取查询字符串值后,我进行了 ajax 调用,这是异步的。 LocationChanged本身就是同步方法,貌似没有异步版本的LocationChanged
。而从LocationChanged内部调用async方法时,async方法设置的值落后了一步。
这是重现:
@page "/investigate"
@implements IDisposable
@inject NavigationManager NM
<h1>Sync: @SyncValue</h1>
<h1>Async: @AsyncValue</h1>
<button @onclick="TriggerLocationChange">Increment</button>
@code {
private string SyncValue;
private string AsyncValue;
private int Counter = 1;
protected override void OnInitialized()
{
NM.LocationChanged += OnLocationChanged;
}
public void Dispose()
{
NM.LocationChanged -= OnLocationChanged;
}
private void OnLocationChanged(object sender, LocationChangedEventArgs args)
{
// sync action, just for comparison
SyncValue = (Counter * 1000).ToString();
DoSomeAsync();
}
private async Task DoSomeAsync()
{
// http call to server
await Task.Delay(1);
AsyncValue = (Counter * 1000).ToString();
}
private void TriggerLocationChange()
{
Counter++;
NM.NavigateTo("investigate?counter=" + Counter);
}
}
@AsyncValue
比 @SyncValue
落后一步。
如何防止从 LocationChanged 内部调用异步方法时滞后?
用异步标记方法不会更改方法的签名,因此您应该这样做:
private async void OnLocationChanged(object sender, LocationChangedEventArgs args)
{
// sync action:
SyncValue = (Counter * 1000).ToString();
await DoSomeAsync();
StateHasChanged();
}
经过大量的试验和错误,这是我的发现:
LocationChanged 运行时尚未设置路由参数值。这在我上面的例子中没有显示,但对我来说很重要。可以从 URL 中手动提取路由参数,或者我们可以等到 blazor 使用 await Task.Delay(1)
.
填充路由参数
在异步方法结束时调用StateHasChanged()
。
According to the documentation 我们应该用 base.InvokeAsync(() => ...)
包装调用
经过这些修改后,OnLocationChanged 变为:
private void OnLocationChanged(object sender, LocationChangedEventArgs args)
{
// ...
base.InvokeAsync(async () =>
{
await Task.Delay(1); // wait for blazor to populate route parameters
await DoSomeAsync();
StateHasChanged();
});
}
我正在使用 NavigationManager.LocationChanged
来捕获查询字符串。获取查询字符串值后,我进行了 ajax 调用,这是异步的。 LocationChanged本身就是同步方法,貌似没有异步版本的LocationChanged
。而从LocationChanged内部调用async方法时,async方法设置的值落后了一步。
这是重现:
@page "/investigate"
@implements IDisposable
@inject NavigationManager NM
<h1>Sync: @SyncValue</h1>
<h1>Async: @AsyncValue</h1>
<button @onclick="TriggerLocationChange">Increment</button>
@code {
private string SyncValue;
private string AsyncValue;
private int Counter = 1;
protected override void OnInitialized()
{
NM.LocationChanged += OnLocationChanged;
}
public void Dispose()
{
NM.LocationChanged -= OnLocationChanged;
}
private void OnLocationChanged(object sender, LocationChangedEventArgs args)
{
// sync action, just for comparison
SyncValue = (Counter * 1000).ToString();
DoSomeAsync();
}
private async Task DoSomeAsync()
{
// http call to server
await Task.Delay(1);
AsyncValue = (Counter * 1000).ToString();
}
private void TriggerLocationChange()
{
Counter++;
NM.NavigateTo("investigate?counter=" + Counter);
}
}
@AsyncValue
比 @SyncValue
落后一步。
如何防止从 LocationChanged 内部调用异步方法时滞后?
用异步标记方法不会更改方法的签名,因此您应该这样做:
private async void OnLocationChanged(object sender, LocationChangedEventArgs args)
{
// sync action:
SyncValue = (Counter * 1000).ToString();
await DoSomeAsync();
StateHasChanged();
}
经过大量的试验和错误,这是我的发现:
LocationChanged 运行时尚未设置路由参数值。这在我上面的例子中没有显示,但对我来说很重要。可以从 URL 中手动提取路由参数,或者我们可以等到 blazor 使用
填充路由参数await Task.Delay(1)
.在异步方法结束时调用
StateHasChanged()
。According to the documentation 我们应该用
包装调用base.InvokeAsync(() => ...)
经过这些修改后,OnLocationChanged 变为:
private void OnLocationChanged(object sender, LocationChangedEventArgs args)
{
// ...
base.InvokeAsync(async () =>
{
await Task.Delay(1); // wait for blazor to populate route parameters
await DoSomeAsync();
StateHasChanged();
});
}