Blazor 从内部NavigationManager.LocationChanged调用异步方法
我正在使用Blazor 从内部NavigationManager.LocationChanged调用异步方法,blazor,blazor-client-side,Blazor,Blazor Client Side,我正在使用NavigationManager.LocationChanged捕获查询字符串。在获得查询字符串值之后,我将进行一个ajax调用,它是异步的。LocationChanged本身是一种同步方法,看起来没有异步版本的LocationChanged。当从LocationChanged内部调用async方法时,async方法设置的值落后一步 这是报告: @page "/investigate" @implements IDisposable @inject NavigationManager
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);
}
}
@page/“调查”
@实现IDisposable
@注入导航管理器NM
Sync:@SyncValue
Async:@AsyncValue
增量
@代码{
私有字符串同步值;
私有字符串值;
专用整数计数器=1;
受保护的覆盖无效OnInitialized()
{
NM.LocationChanged+=OnLocationChanged;
}
公共空间处置()
{
NM.LocationChanged-=OnLocationChanged;
}
私有void OnLocationChanged(对象发送方,LocationChangedEventArgs参数)
{
//同步操作,仅用于比较
SyncValue=(计数器*1000).ToString();
DoSomeAsync();
}
专用异步任务DoSomeAsync()
{
//对服务器的http调用
等待任务。延迟(1);
AsyncValue=(计数器*1000).ToString();
}
私有void TriggerLocationChange()
{
计数器++;
NM.NavigateTo(“调查?计数器=“+计数器”);
}
}
@AsyncValue
比@SyncValue
落后一步
当从内部LocationChanged调用异步方法时,如何防止该方法落后?使用异步标记方法不会更改该方法的签名,因此您应该这样做:
private async void OnLocationChanged(object sender, LocationChangedEventArgs args)
{
// sync action:
SyncValue = (Counter * 1000).ToString();
await DoSomeAsync();
StateHasChanged();
}
经过反复试验,我发现:
wait Task.Delay(1)
填充路由参数
statehaschange()
base.InvokeAsync(()=>…)
private void OnLocationChanged(对象发送方,LocationChangedEventArgs参数)
{
// ...
base.InvokeAsync(异步()=>
{
wait Task.Delay(1);//等待blazor填充路由参数
等待DoSomeAsync();
StateHasChanged();
});
}
您是否尝试使计数器静止<代码>专用整数计数器=1代码>每次加载页面后,此选项将始终设置为1。关闭。您缺少一个statehaschange()代码>在等待DoSomeAsync()之后你对田野的观察很奇怪,我想你误解了什么。.ContinuWith()构造是async/await的替代方法,但不太常用。“当async方法运行时,不要依赖对象字段来获得正确的值。”这是一个错误且无根据的语句。。。使用ContinueWith并不能真正增加任何价值或解决您所面临的问题。您的代码未按预期工作:第一次单击不会产生任何可视更改(查询字符串除外)。第二次单击时,SyncValue和AsyncValue显示值2000,计数器=2。我有一个新的答案,其中变量和计数器的值都是相同的。没有滞后…这里是Blazor的新手。Blazor文档中说“组件的生命周期方法和Blazor引发的任何事件回调都是在同步上下文中执行的。”所以你不需要用InvokeAsync包装,对吗?@pholy实际上我在没有InvokeAsync的情况下试过了,效果很好,但请打开我提供的官方文档的链接,它明确地说我们应该使用InvokeAsync。OnLocationChanged是Blazor引发的一个事件,所以您不需要使用InvokeAsync来获取同步上下文。我引用的是你链接到的部分上面的2段。这就是为什么没有它它也能工作。