MAUI/Blazor混合应用关闭前如何弹出未保存更改提示?
在MAUI/Blazor混合应用中实现关闭前未保存更改提示
要实现这个需求,MAUI本身没有跨平台的「阻止应用关闭」通用API,但可以通过平台特定代码结合Blazor端的状态跟踪来实现,以下是分步方案:
1. 统一跟踪未保存状态
首先在Blazor层创建一个全局服务,用来跟踪是否存在未保存更改:
// 新建服务类 public class UnsavedChangesService { public bool HasUnsavedChanges { get; set; } }
在Program.cs中注册为单例:
builder.Services.AddSingleton<UnsavedChangesService>();
在需要编辑的Blazor组件中注入该服务,当用户修改内容时设置HasUnsavedChanges = true,保存完成后重置为false:
@inject UnsavedChangesService UnsavedService <!-- 组件内容 --> @code { void OnInputChanged() { UnsavedService.HasUnsavedChanges = true; } async Task SaveChanges() { // 保存逻辑 UnsavedService.HasUnsavedChanges = false; } }
2. 平台特定的关闭拦截处理
针对不同平台,编写对应的拦截逻辑:
Windows平台
在Platforms/Windows/App.xaml.cs中,监听主窗口的Closing事件,弹窗确认后决定是否取消关闭:
protected override void OnLaunched(LaunchActivatedEventArgs args) { base.OnLaunched(args); var mainWindow = Application.Current.Windows[0].Handler.PlatformView as Microsoft.UI.Xaml.Window; mainWindow.Closing += MainWindow_Closing; } private void MainWindow_Closing(object sender, Microsoft.UI.Xaml.WindowEventArgs e) { var unsavedService = App.Current.Services.GetService<UnsavedChangesService>(); if (unsavedService?.HasUnsavedChanges == true) { var dialog = new ContentDialog { Title = "未保存的更改", Content = "您有未保存的更改,确定要关闭应用吗?", PrimaryButtonText = "确定关闭", SecondaryButtonText = "取消" }; var result = dialog.ShowAsync().GetAwaiter().GetResult(); if (result == ContentDialogResult.Secondary) { e.Cancel = true; // 取消关闭操作 } } }
Android平台
在Platforms/Android/MainActivity.cs中重写OnBackPressed方法,处理用户按返回键的场景:
public override void OnBackPressed() { var unsavedService = App.Current.Services.GetService<UnsavedChangesService>(); if (unsavedService?.HasUnsavedChanges == true) { new AlertDialog.Builder(this) .SetTitle("未保存的更改") .SetMessage("您有未保存的更改,确定要退出吗?") .SetPositiveButton("确定", (s, e) => base.OnBackPressed()) .SetNegativeButton("取消", (s, e) => { }) .Create() .Show(); } else { base.OnBackPressed(); } }
注意:Android中用户从「最近应用列表」划掉应用时,系统会直接终止进程,无法弹出提示,只能处理返回键场景。
iOS平台
在Platforms/iOS/AppDelegate.cs中重写WillTerminate方法,处理应用即将终止的场景:
public override void WillTerminate(UIApplication application) { var unsavedService = App.Current.Services.GetService<UnsavedChangesService>(); if (unsavedService?.HasUnsavedChanges == true) { var alert = UIAlertController.Create( "未保存的更改", "您有未保存的更改,确定要关闭吗?", UIAlertControllerStyle.Alert); alert.AddAction(UIAlertAction.Create("确定", UIAlertActionStyle.Default, _ => base.WillTerminate(application))); alert.AddAction(UIAlertAction.Create("取消", UIAlertActionStyle.Cancel, _ => { })); var rootVC = UIApplication.SharedApplication.KeyWindow?.RootViewController; rootVC?.PresentViewController(alert, true, null); } else { base.WillTerminate(application); } }
注意:iOS中应用进入后台时不会触发WillTerminate,只有系统强制终止或用户主动关闭(非后台切换)时才会触发。
3. 保留浏览器端的处理
在Blazor的MainLayout.razor中保留浏览器端的beforeunload事件处理,确保Web端正常工作:
@inject UnsavedChangesService UnsavedService @inject IJSRuntime JS @implements IDisposable @code { protected override void OnInitialized() { base.OnInitialized(); if (OperatingSystem.IsBrowser()) { JS.InvokeVoidAsync("setupBeforeUnload", UnsavedService.HasUnsavedChanges); } } public void Dispose() { if (OperatingSystem.IsBrowser()) { JS.InvokeVoidAsync("removeBeforeUnload"); } } }
在wwwroot/js/app.js中添加对应的JS逻辑:
window.setupBeforeUnload = (hasUnsaved) => { if (hasUnsaved) { window.addEventListener('beforeunload', (e) => { e.preventDefault(); e.returnValue = ''; return ''; }); } }; window.removeBeforeUnload = () => { window.removeEventListener('beforeunload', (e) => { e.preventDefault(); e.returnValue = ''; return ''; }); };
内容的提问来源于stack exchange,提问作者BlakkM9
相关产品推荐
相关产品推荐

