3

This answer shows how to trigger the onbeforeunload event in a WebBrowser control in the following way:

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);
}

But now trying to move away from IE11 (as used by WebBrowser) to Edge Chromium with the WebView2 control, I can't figure out how to do the same thing in WebView2.

The dialog shows correctly when navigating the WebView2 to another page. The problem comes when the user closes the application or the window containing the WebView2. It then just closes without showing any dialog.

That's what the code above does for the WebBrowser control, when closing the application the (on)beforeonload event is triggered in the IE11 browser and a bool is returned. True if the user pressed "Leave" or there isn't an beforeonload event active and false if the user pressed "Stay on the page".

Short of calling ExecuteScriptAsync("onbeforeunload();") (which doesn't work when setting the event with window.addEventListener("beforeunload", function(event) { ... });) how can the same be done in WebView2?


Edit:

The problem is that I don't want to show the dialog always when closing, unless I really have to. I only want to show it if the page has unsaved changes (and it communicates that in the beforeunload event in JavaScript). The only way I know how handle that in the C#-code is by triggering the built in onunload event showing the beforeunload dialog in the browser. That is exactly what the ActiveXInstance.ExecWB(OLECMDID_ONUNLOAD) does for the WebBrowser control and IE11.

It may simply not be possible to trigger that event in WebView2/Chromium in the same way? That's really what I'm asking. I've tried calling JavaScripts in the FormClosing event, but the application just closes w/o waiting for the response.

I guess the only other option is to remove the x-close button and use a custom close button that can do the needed checks and then close the application.

Erik Bunnstad
  • 96
  • 2
  • 7
  • Show us, what you want to do in the `beforeunload` event, then we can give you a a better answer (in general `beforeunload` should be avoided). There's no activeX in Edge, so you can't use the code, you show. – Poul Bak Apr 26 '21 at 15:47
  • Can't you simply use the `FormClosing` event? – Poul Bak Apr 26 '21 at 15:54

2 Answers2

0

This is working for me. You can combine it with a form closing or something. Don't forget to properly detach events / dispose where proper. This is just a sample.

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();
            }
        }
Nikki9696
  • 6,260
  • 1
  • 28
  • 23
  • 1
    Thanks for the answer, but this just replaces the existing built in dialog. And dosn't work when closing the Form, since there's no way to call the page at that point to trigger a dialog, which is why I need a way to trigger the browser's dialog. e.GetDeferral(); also just postpones the event and freezes the browser until Complete() is called on the Deferral. – Erik Bunnstad Apr 27 '21 at 10:40
0

As I wanted to do the same thing, it isn't possible because according to a comment in WebView2Feedback github:

When Close() is called on the WebView2 instance, we will not be showing the beforeunload dialog box regardless of the flag value for AreDefaultScriptDialogsEnabled. This decision was made as the app starts the shutdown process before the browser handles the event, and we cannot fetch any session information even if the user clicks on Cancel.

Wizard
  • 2,961
  • 2
  • 13
  • 22