UWP WebView仅触发最后一次请求的NavigationCompleted事件,如何让每次都触发?
问题分析与解决方案
这个问题的核心原因很明确:WebView的导航操作是异步且排他的——当你在循环里连续调用NavigateToLocalStreamUri时,后一次的导航请求会立刻终止前一次还在进行中的导航流程。这就导致前两次的导航还没来得及完成,就被下一次请求打断了,自然不会触发NavigationCompleted事件,只有最后一次没有被打断的导航能走完完整流程,触发对应的完成事件。
要解决这个问题,你需要让导航操作串行执行:等待上一次导航完全完成(不管成功还是失败)后,再发起下一次导航请求。下面是具体的实现方案:
异步等待导航完成的实现
我们可以用TaskCompletionSource来包装NavigationCompleted(以及NavigationFailed)事件,把异步事件转换成可等待的Task,从而实现循环中的串行导航:
// 把循环改成异步方法 private async Task NavigateWithSequentialCompletion() { for (int i = 0; i < 3; i++) { var tcs = new TaskCompletionSource<bool>(); // 定义导航完成的事件处理程序 void NavigationCompletedHandler(object sender, NavigationCompletedEventArgs e) { // 先取消订阅,避免内存泄漏 _webView.NavigationCompleted -= NavigationCompletedHandler; _webView.NavigationFailed -= NavigationFailedHandler; tcs.SetResult(true); } // 定义导航失败的事件处理程序(可选但建议加上,避免任务永远等待) void NavigationFailedHandler(object sender, NavigationFailedEventArgs e) { _webView.NavigationCompleted -= NavigationCompletedHandler; _webView.NavigationFailed -= NavigationFailedHandler; // 可以根据需要抛出异常或者标记失败 tcs.SetException(new InvalidOperationException($"导航失败: {e.WebErrorStatus}")); } // 订阅事件 _webView.NavigationCompleted += NavigationCompletedHandler; _webView.NavigationFailed += NavigationFailedHandler; // 发起本次导航 _webView.NavigateToLocalStreamUri(url[i], resolver); // 等待本次导航完成(成功或失败) await tcs.Task; } }
方案说明
- 串行执行逻辑:通过
await tcs.Task,我们强制循环在发起下一次导航前,等待当前导航的NavigationCompleted或NavigationFailed事件触发,确保每一次导航都能走完完整的生命周期。 - 事件清理:每次导航完成/失败后,立刻取消对事件的订阅,避免因为重复订阅导致的内存泄漏和重复触发问题。
- 异常处理:加入
NavigationFailed的处理,防止因为导航出错导致TaskCompletionSource一直处于未完成状态,造成程序卡住。
调用这个异步方法时,记得在合适的地方用await,比如在按钮点击事件里:
private async void Button_Click(object sender, RoutedEventArgs e) { await NavigateWithSequentialCompletion(); }
这样修改后,每一次循环的导航都会依次触发NavigationStarting和对应的NavigationCompleted(或NavigationFailed)事件,不会再出现前面的导航被打断的情况。
内容的提问来源于stack exchange,提问作者user2706
相关产品推荐
相关产品推荐

