WPF WebBrowser - open links in default browser

2019-08-11 01:04发布

问题:

I am using a WPF System.Windows.Controls.WebBrowser control to show some HTML content that is downloaded from a service. Sometimes the HTML contains URLs ("a" elements) that should be clickable.

By default, when such an URL is clicked it opens in Internet Explorer. I want them to open in the default browser instead.

Note I am talking specifically about the WPF WebBrowser. There are tons of solutions for the WinForms browser, but they do not work for the WPF browser.

The most common "solution" is to handle the Navigating event, cancel it and then do your own thing with the URL. This does not work because the Navigating event is not called when I click a link in the HTML.

Another solution I found does seem to work, but only sometimes for some strange reason: https://stackoverflow.com/a/9111151/573249

I now have the following code, using the method from the link above:

private void WebBrowser_OnNavigating(object sender, NavigatingCancelEventArgs e)
{
    // Just for demonstration purposes
    // This is NOT CALLED when a link is clicked

    Debug.WriteLine("> Navigating called.");

    if (e.Uri == null)
    {
        Debug.WriteLine(">> URI was null.");
        return;
    }
    e.Cancel = true;
    Process.Start(e.Uri.AbsolutePath);
    Debug.WriteLine(">> Navigation cancelled and opened in default browser.");
}

private void WebBrowser_OnLoadCompleted(object sender, NavigationEventArgs e)
{
    Debug.WriteLine("> LoadCompleted called.");

    mshtml.HTMLDocument doc;
    doc = (mshtml.HTMLDocument) webBrowser.Document;
    mshtml.HTMLDocumentEvents2_Event iEvent;
    iEvent = (mshtml.HTMLDocumentEvents2_Event) doc;
    iEvent.onclick += new mshtml.HTMLDocumentEvents2_onclickEventHandler(ClickEventHandler);

    Debug.WriteLine("> LoadCompleted finished!");
    Debug.WriteLine("------");
}

private bool ClickEventHandler(mshtml.IHTMLEventObj e)
{
    // This finally opens the URL in the default browser
    // The method is called only 20% of the time.

    Debug.WriteLine(">> Click event handler called.");

    var a = (mshtml.HTMLAnchorElement) e.srcElement;
    Process.Start(a.href);
    return false;
}

When I click a link, it seems to work maybe 20% of the time. In those cases, "ClickEventHandler" is called, and the link is opened in the default browser. In the other 80% of the cases, "ClickEventHandler" is never called (and the link opens in IE), even though "OnLoadCompleted" finishes without exceptions.

There does not seem to be a pattern, although when it fails once it seems to keep failing forever on the same document until I re-load the HTML. After re-loading it is back to 20% chance of working.

What's going on?

回答1:

Hi I had exactly the same problem. OnMouseDown event was fired just sometimes. And I couldn't figure this out. I just gave up and used WinForm WebBrowser instead. Then you don't need reference for MSHTML but you need reference for System.Windows.Forms and System.Windows.Interactivity.

XAML

xmlns:wf="clr-namespace:System.Windows.Forms;assembly=System.Windows.Forms"

<WindowsFormsHost>
  <wf:WebBrowser x:Name="WbThumbs"/>
</WindowsFormsHost>

C#

public WMain() {
  System.Windows.Forms.Application.EnableVisualStyles();
  InitializeComponent();

  WbThumbs.DocumentCompleted += WbThumbsOnDocumentCompleted;
  WbThumbs.Navigate("www.blabla.com");
}

private void WbThumbsOnDocumentCompleted(object sender, System.Windows.Forms.WebBrowserDocumentCompletedEventArgs e) {
  if (WbThumbs.Document == null) return;
  WbThumbs.Document.Click += WbThumbs_Click;
}

private void WbThumbs_Click(object sender, System.Windows.Forms.HtmlElementEventArgs e) {
  var doc = WbThumbs.Document;
  var src = doc?.GetElementFromPoint(e.ClientMousePosition);
  if (src == null) return;
  //...
}