Search code examples
c#winformscefsharp

How do I keep the CefSharp browser from opening 2 windows when following an html link?


I'm using the CefSharp browser to display the contents of emails. I pull the BodyHtmlText out of a parsed email and load it into the browser using browser.LoadHtml(BodyHtmlText, "http:\\pixemail.com\");. I want links in the BodyHtmlText to open in the system default browser, so I've implemented a BrowserRequestHandler and tell the browser to use it by setting browser.RequestHandler = BrowserRequestHandler;

This works well, except when the link anchor tag has a <a...target="_blank">. When it does, clicking the link opens two new browser windows; one with the link target page as expected, and another that is just empty. BrowserRequestHandler.OnBeforeBrowse() is called only once, even though 2 windows are opened.

How do I get rid of the empty window?

If I don't install a BrowserRequestHandler, links with target="_blank" open in a new browser without the extra window, but regular links (without target="_blank"), open in the app's CefSharp browser window, which I don't want. If, in BrowserRequestHandler.OnBeforeBrowse() I could detect that the link had target="_blank", I could let the CefBrowser handle it and get the behavior I want. Or is there some other way to configure and use the CefSharp browser to get the behavior I want?

A slightly modified version of CefSharp.MinimalExample.WinForms exhibits the same problem. My BrowserRequestHandler looks like this:

public class BrowserRequestHandler : RequestHandler {
    protected override bool OnBeforeBrowse(IWebBrowser browserControl, IBrowser browser, IFrame frame,
      IRequest request, bool userGesture, bool isRedirect) {
        // Open in external default browser (chrome)
        if (!request.Url.StartsWith("file:") && !request.Url.StartsWith("devtools:")
          && !request.Url.StartsWith("chrome-devtools:") && !request.Url.Contains("pixemail.com")) {
            Console.WriteLine($"start new browser at {request.Url}");
            System.Diagnostics.Process.Start(request.Url);
            return true;
        }
        return false;   // let Cef handle the browse request
    }
}

The changes to CefSharp.MinimalExample.WinForms.BrowserForm are:

    string htmlPageFromEmail;

    public BrowserForm() {
        InitializeComponent();
        htmlPageFromEmail = File.ReadAllText("test-email.html");
        //...
        browser = new ChromiumWebBrowser("http://pixemail.com/");   // a dummy web address
        //...
        BrowserRequestHandler = new BrowserRequestHandler();
        browser.IsBrowserInitializedChanged += OnIsBrowserInitializedChanged;
        //...
        browser.Visible = true;
    }

    private void OnIsBrowserInitializedChanged(object sender, EventArgs e) {
        var b = ((ChromiumWebBrowser) sender);
        this.InvokeOnUiThreadIfRequired(() => {
            b.LoadHtml(htmlPageFromEmail, "http://pixemail.com/");
            b.Focus();
        });
    }

My test-email.html file which I use to simulate an email BodyHtmlText string an is:

  <html xmlns="http://www.w3.org/1999/xhtml">
    <head></head>
    <body>
      <br><br>Bad link. Opens 2 windows:
      <a href="https://www.youtube.com/watch?v=_7Yw8qMDips&amp;fbclid=IwAR1rGIK9KJukB4_KV5J-E3hqgfFPFZG8scobzKw_aw3jcUnrQWafr4Iw8bc" rel="nofollow" target="_blank" class="enhancr_card_3679327690">Jonny Quest Opening Titles in Stop Motion</a>
      <br><br>Good link. Opens 1 window:
      <a href="https://mewe.com/group/5e35fe0f260e8853cadbe7b7">https://mewe.com/group/5e35fe0f260e8853cadbe7b7</a>
      <br><br>
    </body>
  </html>

I'm using version CefSharp/84 on a Windows 10 PC and Visual Studio 2019 with an x64 platform target.


Solution

  • From memory OnBeforePopup is called before OnBeforeBrowse, so CEF internally creates the popup window then you cancel the navigation resulting in an empty window. In your OnBeforeBrowse implementation you should find Browser.IsPopup is true in cases where the link has the target attribute.

    In short you are canceling the navigation too late, the popup window has already been created.

    Two options are