Search code examples
c#winformswebview2

WebView2 - intercept and prevent/cancel anchor navigation


In my WinForms app I used WebView2 to show thrird-party content. When user clicks the link (or other navigation element) inside the webView, the target link should be opened in the default browser (not in the webView). For most cases I was able to implement desired behaviour with NewWindowRequested and NavigationStarting events. But for anchor navigation inside the current page (<a href="#my_anchor">) these events are not firing.

There is a SourceChanged event, which is fired in case on anchor navigation, and it even allows to determine that this is in-page navigation by checking IsNewDocument, but it does not allow to cancel the navigation.

I was thinking about js-based solution, something like subscribing to click events for all a tags or even for whole document with further filtering. But I realized that such a solution will not work in many non-trivial cases, including

  • dynamically created a elements
  • keyboard navigation (TAB to select link, Enter to initiate action, so no click event)
  • the cases when there are a lot of elements (img, etc) inside a element and user clicked on such an internal element
  • when navigation is initiated with js

So, is the way exists to handle and cancel any navigation, including anchors in the current page?


Solution

  • There is a GitHub issue https://github.com/MicrosoftEdge/WebView2Feedback/issues/2217 that confirms that there is no way to trap/cancel the anchor navigation inside the page. And this behaviour is considered a bug which should be fixed.

    My current workaround looks like this: subscribe to the SourceChanged event and use the following handler

    private void WebBrowser_SourceChanged(object? sender, CoreWebView2SourceChangedEventArgs e)
    {
        Text = webBrowser.Source.ToString();
        Debug.WriteLine(webBrowser.Source.ToString());
        if (!e.IsNewDocument && webBrowser.Source.ToString() != Url)
        {
            //Crutch!!!
            //There is no normal way to catch and cancel anchor navigation on a *current* page 
            //like <a href=“#test”>. You can only catch it when the address changes. 
            //And in this case open the new address in the default browser, 
            //and the built-in browser is navigated back as if the anchor navigation
            //never happened.
            //TODO: Remove/rework when MS will fix https://github.com/MicrosoftEdge/WebView2Feedback/issues/2217.
            webBrowser.GoBack();
            OpenInDefaultBrowserIfNeeded(webBrowser.Source.ToString());
        }
    }
    

    The Url in the code above is the url of the page the browser was navigated (e.g. the "current page", which contains the anchor which was clicked).