You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 19:23:17