MAUI Blazor学习17-NavigationLock阻止页面回退
MAUI Blazor学习17-NavigationLock阻止页面回退
MAUI Blazor系列目录
- MAUI Blazor学习1-移动客户端Shell布局 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习2-创建移动客户端Razor页面 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习3-绘制ECharts图表 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习4-绘制BootstrapBlazor.Chart图表 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习5-BLE低功耗蓝牙 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习6-扫描二维码 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习7-实现登录跳转页面 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习8-支持多语言 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习9-VS Code开发调试MAUI入门 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习10-BarcodeScanner扫描二维码 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习11-百度地图定位 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习12-文件另存为 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习13-打开文件 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习14-选择目录 - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习15-采用html2pdf.js生成pdf - SunnyTrudeau - 博客园 (cnblogs.com)
- MAUI Blazor学习16-连续按BACK退出APP - SunnyTrudeau - 博客园 (cnblogs.com)
在APP功能开发中,有时候要阻止页面回退,比如,当前填写的内容没有保存,长时间运行的任务没有完成等等。本来想着拦截BACK按键事件来实现,后来发现MAUI Blazor有现成的组件NavigationLock,可以非常简单的实现阻止页面回退的功能。参考微软官网:
https://learn.microsoft.com/zh-cn/aspnet/core/blazor/fundamentals/routing?view=aspnetcore-8.0#handleprevent-location-changes
只要呈现导航事件,NavigationLock 组件就会将其拦截,除非决定继续或取消,否则将一直有效“锁定”任何给定的导航。 当导航拦截的范围可以限定为组件的生存期时,使用 NavigationLock。
NavigationLock 参数:
ConfirmExternalNavigation 设置浏览器对话框以提示用户确认或取消外部导航。 默认值为 false。 显示确认对话框需要在使用浏览器地址栏中的 URL 触发外部导航之前与页面进行初始用户交互。 有关交互要求的详细信息,请参阅 Window:beforeunload 事件(MDN 文档)。
OnBeforeInternalNavigation 为内部导航事件设置回调。
基于MaBlaApp项目,添加NavigationLock组件阻止页面回退功能。模拟实现一个需求,当前页面正在运行长时间任务,需要首先停止任务,才能退出页面。
D:\Software\gitee\mauiblazorapp\MaBlaApp\Pages\LongTimeTask.razor
@page "/longtimetask" <h3>阻止长时间任务页面回退</h3> <div class="d-flex justify-content-between m-1"> <button class="btn btn-primary mx-2 @BtnStartCss" @onclick=StartTaskAsync>开始长时间任务</button> <button class="btn btn-danger mx-2 @BtnStopCss" @onclick=@(() => StopTaskAsync(false))>停止长时间任务</button> </div> <p class="m-1">任务进度:@ProcessMsg</p> <div class="progress m-1" style="height:10px"> <div class="progress-bar bg-primary" style="width:@Process%"></div> </div> <NavigationLock ConfirmExternalNavigation="true" OnBeforeInternalNavigation="OnBeforeInternalNavigation" /> @code { private string BtnStartCss => IsBusy ? "disabled" : ""; private string BtnStopCss => IsBusy ? "" : "disabled"; private bool IsBusy = false; private CancellationTokenSource Cts; private int Process = 0; private string ProcessMsg = ""; //开始长时间任务 private async Task StartTaskAsync() { if (IsBusy) return; if (Cts is not null) return; try { IsBusy = true; Cts = new CancellationTokenSource(); var startTime = DateTimeOffset.Now; Process = 0; ProcessMsg = "..."; StateHasChanged(); using var timer = new PeriodicTimer(TimeSpan.FromSeconds(1)); while (await timer.WaitForNextTickAsync(Cts.Token)) { Process += 10; ProcessMsg = $"耗时{DateTimeOffset.Now.Subtract(startTime).TotalSeconds:N0}秒,进度{Process}%"; StateHasChanged(); if (Process >= 100) { ProcessMsg += ",任务圆满完成"; break; } } } catch (OperationCanceledException) { ProcessMsg += ",任务提前终止"; System.Diagnostics.Debug.WriteLine($"{DateTimeOffset.Now:G}, {ProcessMsg}"); } finally { Cts.Dispose(); Cts = null; IsBusy = false; } StateHasChanged(); } //停止长时间任务 private async Task StopTaskAsync(bool forceStop = false) { if (!IsBusy) return; if (!forceStop) { //询问用户是否结束任务 bool isStopTask = await App.Current.MainPage.DisplayAlert("警告", "任务进行中,是否结束任务?", "结束任务", "继续任务"); if (!isStopTask) return; } if (Cts is not null) Cts.Cancel(); } //检查能否安全退出页面 private async Task OnBeforeInternalNavigation(LocationChangingContext context) { //如果当前任务正在运行中,请用户先停止任务,才能退出页面 if (IsBusy) { bool isStopTask = await App.Current.MainPage.DisplayAlert("警告", "任务进行中,是否结束任务?", "结束任务", "继续任务"); if (isStopTask) { //强制结束任务 await StopTaskAsync(true); } else { //阻止页面退出 context.PreventNavigation(); } } } }
在VS2022自带的安卓模拟器上调试运行,开始长时间任务后,点击BACK键退出页面,弹窗询问用户,如果选择继续任务,则阻止页面退出,测试效果符合预期。
DEMO代码地址:https://gitee.com/woodsun/mauiblazorapp