How can I prevent a WebView control from opening a browser window?


A customer had an application that used a UWP WebView control. Some Web sites open links in a new window by using techniques like TARGET=_blank. When the user clicks on such a link, it opens in a Web browser. The customer wanted to know how to prevent this.

To do this, you can handle the New­Window­Requested event. You can mark the event as Handled, in which case the system will consider the action complete and will not send the request to the user's default Web browser.

<!-- XAML -->
<WebView NewWindowRequested="OnNewWindowRequested" />

// C# code-behind
void OnNewWindowRequested(WebView sender, WebViewNewWindowRequestedEventArgs e) 
{ 
    // Block all requests to open a new window
    e.Handled = true; 
} 

You can inspect the Referrer and Uri properties to learn more about what triggered the new window.

  • Referrer is the page that wants to open the window.
  • Uri is the page that it wants to open.

If your handler is a coroutine, then you must set Handled = true before performing any await operations, because the handler returns to its caller as soon as you perform an await, and the rest of the handler runs as an asynchronous task.

Comments (10)

  1. Aybe One says:

    Holy cow, Visual Studio 2019 Preview is still using IE11 for ‘Web Browser’ window !

    @Raymond

    I couldn’t post this comment from my Samsung Galaxy, when pressed, the ‘Post Comment’ button does absolutely nothing (using the stock browser on the phone).

    1. Gee Law says:

      IE11 is pretty much the only choice — the last time I saw EdgeHTML WebView for Win32 Desktop, it was still in a very early stage of preview. Of course an app could implement its own WebView, but that’s not worth it for VS. (It’s worth it for browsers.)

      On Safari on iPhone, the Post Comment button doesn’t always work. Haven’t found out what the controlling factors are.

      1. cheong00 says:

        Agreed.

        Even if you’re not limiting it to UWP, although there are equivalent on Firefox(GeckoFX) and Chrome(CEF actually), you don’t actually want use it because often sites requires you to use maybe latest 3 versions of them, and their version number sky-rockets rapidly. This mean your application will have much shorter release cycle than you probably want if you need to host maybe embedded Google Map in it.

        And given it’s UWP, you don’t want to require people to download and install extra browser package in order to use it (even if it’s do-able), and it probably won’t work on Win10S.

  2. The word coroutine caught me for a second. Not because I don’t know what it is (I do) but because it reminded me of the “kernel coloured glasses” comment often found in this blog (excellent term BTW)
    In this case, I’d have usually seen this referred to as an async void method, since coroutine is not often used in the c# world but would be quite at home, and the common term, in other languages / ecosystems.
    Just stood out, that’s all. I actually think coroutine is a pretty nice term for it.

  3. cheong00 says:

    I’ve written a website scraping application (a WinForm one) about a year before, handled the NewWindowRequested event, set ScriptErrorsSuppressed to true, yet when allow it to run overnight over a web-archive + AJAX site, there’s about 3 to a dozen new browser window opened by it.

    Not sure what is the reason, but I remember that if I waited that page to fully loaded (not just onload) then issue the next navigate command (and there’s one other fix that I can’t remember), no new window is opened this time.

    Still can’t figure out what the problem is, but as long as it can run, it’s fine to me.

    Btw, the biggest challenge we faced is string interning. After the whole night of web scraping, the memory consumption grows so high that, I decided to let it restart itself after job is done. Currently you cannot free the internal table for string interning unless you unload the application domain, but I really hope they CLR folks can create something like interning table version of GC.Collect() for cases like this, where you’re sure the table holded very long strings that you’ll never use again (actually I think it applies to literally all text processing applications as well. even if you use StringBuilder you’ll unevitably use string from time to time).

  4. Andomar_ says:

    The bit about returning “as soon as you perform an await” surprises me. I’d expect the handler to wait. Where can I find out more about this? Is the fact that Raymond mentions “coroutine” relevant for this behavior?

    1. The handler is waiting asynchronously for the “await” to complete. It does this by scheduling additional work to take place when the await completes, and then returning to its caller. The caller sees that the handler has returned and checks the Handled property.

      1. Andomar_ says:

        Thanks for your reply! I’ve read the linked article and discussed it with a colleague, but we still don’t understand. How can the function calling the handler know when the handler enters an await? What happens if you set the handled output parameter, then use an await, and then set the handled parameter to another value?

        1. The caller doesn’t know that the handler entered an await. All the caller sees is that the handler returned. That’s why you need to set Handled before awaiting. Because as far as the caller is concerned, you’ve returned.

          1. Andomar_ says:

            Thanks, very interesting. I wonder how I could store the result of an async method in Handled. One idea is to construct a Task with the async function as Action and then call Task.RunSynchronously(). This would hopefully keep the thread blocked and prevent the handler from returning. What would you think of this approach?

Skip to main content