在 WebView2 中触发 onbeforeunload

Posted

技术标签:

【中文标题】在 WebView2 中触发 onbeforeunload【英文标题】:Triggering onbeforeunload in WebView2 【发布时间】:2021-07-19 21:29:12 【问题描述】:

这个answer 展示了如何通过以下方式在WebBrowser 控件中触发onbeforeunload 事件:

protected override void OnFormClosing(FormClosingEventArgs e)

    if (!this.formsWebBrowser.IsDisposed)
    
        //// Generate SHDocVw.dll: Visual Studio Developer Command Prompt "tlbimp.exe ieframe.dll /out: C:\temp\SHDocVw.dll",
        var activeX = this.formsWebBrowser.ActiveXInstance;
        var input = Type.Missing;
        object leavePage = true;
        ((SHDocVw.WebBrowser)activeX).ExecWB(
            SHDocVw.OLECMDID.OLECMDID_ONUNLOAD,
            SHDocVw.OLECMDEXECOPT.OLECMDEXECOPT_DODEFAULT,
            ref input,
            ref leavePage);
        if (!(bool)leavePage)
        
            e.Cancel = true;
            return;
        
    

    base.OnFormClosing(e);

但现在尝试使用 WebView2 控件从 IE11(WebBrowser 使用)迁移到 Edge Chromium,我不知道如何在 WebView2 中做同样的事情。

将 WebView2 导航到另一个页面时,对话框正确显示。 当用户关闭应用程序或包含 WebView2 的窗口时,就会出现问题。 然后它只是关闭而不显示任何对话框。

这就是上面代码对 WebBrowser 控件所做的事情,当关闭应用程序时,IE11 浏览器中会触发 (on)beforeonload 事件并返回一个布尔值。如果用户按下“离开”或没有激活 beforeonload 事件,则为 true;如果用户按下“留在页面上”,则为 false。

缺少调用 ExecuteScriptAsync("onbeforeunload();") (使用 window.addEventListener("beforeunload", function(event) 设置事件时不起作用。 .. );) 如何在 WebView2 中做同样的事情?


编辑:

问题是我不想在关闭时总是显示对话框,除非我真的必须这样做。 我只想在页面有未保存的更改时显示它(并且它在 javascript 中的 beforeunload 事件中传达了这一点)。 我知道如何在 C# 代码中处理该问题的唯一方法是触发内置的onunload 事件,在浏览器中显示beforeunload 对话框。 这正是 ActiveXInstance.ExecWB(OLECMDID_ONUNLOAD) 对 WebBrowser 控件和 IE11 所做的。

可能根本不可能以相同的方式在 WebView2/Chromium 中触发该事件?这就是我要问的。 我尝试在 FormClosing 事件中调用 JavaScript,但应用程序只是关闭而不等待响应。

我想唯一的其他选择是删除 x-close 按钮​​并使用自定义关闭按钮,该按钮可以进行所需的检查,然后关闭应用程序。

【问题讨论】:

beforeunload事件中告诉我们你想做什么,然后我们可以给你一个更好的答案(一般beforeunload应该避免)。 Edge 中没有 activeX,所以你不能使用代码,你显示。 你不能简单地使用FormClosing事件吗? 【参考方案1】:

这对我有用。您可以将其与表单关闭或其他内容结合使用。不要忘记在适当的地方正确分离事件/处置。这只是一个示例。

public partial class Form2 : Form
    
        public Form2()
        
            InitializeComponent();
        

        private void Form2_Load(object sender, EventArgs e)
        
            DoWork();
        

        private async Task DoWork()
        
            await webView21.EnsureCoreWebView2Async();
            webView21.CoreWebView2.Settings.AreDefaultScriptDialogsEnabled = false;
            webView21.CoreWebView2.ScriptDialogOpening += CoreWebView2_ScriptDialogOpening;
            await webView21.CoreWebView2.AddScriptToExecuteOnDocumentCreatedAsync("window.addEventListener('beforeunload', function(e)  return event.returnValue = 'prompt';);");

            webView21.Source = new Uri("https://www.google.com");
        

        private void CoreWebView2_ScriptDialogOpening(object sender, Microsoft.Web.WebView2.Core.CoreWebView2ScriptDialogOpeningEventArgs e)
        
            if (MessageBox.Show("do you want to leave", "Leave?", MessageBoxButtons.OKCancel) == DialogResult.OK)
            
                e.Accept();
            
            else
            
                e.GetDeferral();
            
        

【讨论】:

感谢您的回答,但这只是替换了现有的内置对话框。并且在关闭表单时不起作用,因为此时无法调用页面来触发对话框,这就是为什么我需要一种方法来触发浏览器的对话框。 e.GetDeferral();也只是推迟事件并冻结浏览器,直到在 Deferral 上调用 Complete()。

以上是关于在 WebView2 中触发 onbeforeunload的主要内容,如果未能解决你的问题,请参考以下文章

是否可以在 Activex 中使用 WebView2?

在异步任务中并行使用 WebView2

操作系统中未安装webview2

在 WebResourceRequested 事件中为 WebView2 设置 cookie

在 Webview2 (WPF) 中管理对话框

如何在控制台应用程序中使用 WebView2