0

Please provide the code snippet to create a tab instead of open a page in new window when click on the links in the webview2 - Edge in C# windows form.

Followed the below steps.

  1. Drag the webview2 control on C# windows form and update the source property link: https://example.com

  2. https://example.com site opened successfully in the webview2

  3. click on few links in the site - https://example.com and it opens the new window and looking for open this one in the new tab instead of open it in new window

  4. This event webView.CoreWebView2.NewWindowRequested never hit when debug the code. In case if this webView.CoreWebView2.NewWindowRequested event raised then no navigate method is available on webview class and its available on corewebview2 classs and getting the null reference exception if we use this.

user1158993
  • 19
  • 1
  • 3
  • What exactly is the problem? – Dennis Kozevnikoff Jul 08 '20 at 16:40
  • If we click on links (Anchor tags with target=_blank) in the website which is opened through WebView2 and links are opening in new webview window. Need to create a program to display that links pages in the tab. – user1158993 Jul 08 '20 at 18:15
  • I'm in favor of Davis's opinion. You need to create your own UI to open link in tab. There's no build in support for this in WebView2. We can handle the `New­Window­Requested` event to prevent opening a browser window. You could refer to [this article](https://devblogs.microsoft.com/oldnewthing/20190102-00/?p=100615). If the event can't be fired, you could provide a minimal code to reproduce the issue so that we can have a test. Besides, [this sample](https://github.com/MicrosoftEdge/WebView2Browser) shows how to use tabs in webview2 but it uses c++. – Yu Zhou Jul 09 '20 at 06:35

2 Answers2

3

For the sake of completeness, I was able to achieve the same thing thanks to David Risney's explanation. Unfortunately it didn't include any code, but I achieved this using 1.0.721-prerelease and Microsoft.WebView2.FixedVersionRuntime.87.0.664.66.x64:

Program.cs:

using System;
using System.Windows.Forms;

namespace TestApp1
{
    static class Program
    {
        public static Microsoft.Web.WebView2.Core.CoreWebView2Environment WebView2Environment;

        [STAThread]
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
            Application.Run(new Form1());
        }
    }
}

Form1.cs:

using System;
using System.Windows.Forms;

namespace TestApp1
{
    public partial class Form1 : Form
    {
        public Microsoft.Web.WebView2.Core.CoreWebView2Deferral Deferral;
        public Microsoft.Web.WebView2.Core.CoreWebView2NewWindowRequestedEventArgs Args;

        public Form1()
        {
            InitializeComponent();
            webView21.CoreWebView2InitializationCompleted += webView21_CoreWebView2InitializationCompleted_1;
        }

        private void CoreWebView2_NewWindowRequested(object sender, Microsoft.Web.WebView2.Core.CoreWebView2NewWindowRequestedEventArgs e)
        {
            Form1 f = new Form1();
            f.Args = e;
            f.Deferral = e.GetDeferral();
            f.Show();
        }

        private async void Form1_Load(object sender, EventArgs e)
        {
            if (Program.WebView2Environment == null)
                Program.WebView2Environment = Microsoft.Web.WebView2.Core.CoreWebView2Environment.CreateAsync(@"C:\Users\Dragon\Downloads\Microsoft.WebView2.FixedVersionRuntime.87.0.664.66.x64", $@"C:\Users\Dragon\Desktop\Test{Guid.NewGuid()}").Result;
            await webView21.EnsureCoreWebView2Async(Program.WebView2Environment);
            webView21.Source = new Uri("http://www.google.com");
        }

        private void webView21_CoreWebView2InitializationCompleted_1(object sender, Microsoft.Web.WebView2.Core.CoreWebView2InitializationCompletedEventArgs e)
        {
            if (!e.IsSuccess) { MessageBox.Show($"{e.InitializationException}"); }

            if (Deferral != null)
            {
                Args.NewWindow = webView21.CoreWebView2;
                Deferral.Complete();
            }

            webView21.CoreWebView2.NewWindowRequested += CoreWebView2_NewWindowRequested;
        }

        private void button1_Click(object sender, EventArgs e)
        {
            webView21.ExecuteScriptAsync($@"window.open('http://www.bing.com', '_blank');");
        }
    }
}

So the way this works is kinda weird: To spawn a new window, you can do it through JavaScript using ExecuteScriptAsync. In this case I'm opening a new window to bing.com. So, that makes a call to CoreWebView2_NewWindowRequested. For the event to pass and the code to work (otherwise it will freeze) it must go through it all. So, you cannot set the NewWindow property of the CoreWebView2NewWindowRequestedEventArgs inside the event that's currently happening.

The solution is to take the event data (args & deferral) to the new form, show it, and upon load and after the CoreWebView2 property of the control is not null / has initialized, by calling CoreWebView2InitializationCompleted, check if args/deferral are not null and then call the defer as Complete() (this is basically like a JS promise) AND here you can set the NewWindow property as CoreWebView2 has been initialized and therefore it's not null.

Hopefully this will answer your question and future readers. With this code, I was able to make it work.

DARKGuy
  • 843
  • 1
  • 12
  • 34
  • just looking at all the NewWindowRequested questions. Doesn’t your above code always navigate to Google irrespective of what the uri in the newwindowrequested event is? – darbid Mar 31 '21 at 19:54
  • The first instance that opens, yes. The second one is spawned by window.open() which in turns triggers the NewWindowRequested event with an URL already set to bing.com. If you want to change that you could, by setting the Url property after the defer() I think. – DARKGuy Apr 01 '21 at 02:32
  • Ok thanks I see it now. The load event will fire before the initialization of the browser event fires for new forms. – darbid Apr 01 '21 at 16:50
2

There's no built in support for tabs in WebView2. However, you can intercept new windows with the NewWindowRequested event and provide your own CoreWebView2 to be that new window, and place that CoreWebView2 how you like in your UI. For instance the new CoreWebView2 could be placed in your UI to look like a new tab. (It sounds like that's what you're doing, but declaring it explicitly here just to ensure that I'm correctly understanding your scenario.)

Regarding the null WebView2.CoreWebView2 property, you can call EnsureCoreWebView2Async and await the returned task or you can set the WebView2.Source property and wait for the CoreWebView2Ready event to dispatch in order for the WebView2.CoreWebView2 property to be filled in. Its null before that.

Additionally, if you need to get the CoreWebView2 to fill in the NewWindowRequestedEventArg's NewWindow property, since the above steps for obtaining the CoreWebView2 from a WebView2 instance are both asynchronous, you'll need to call the NewWindowRequestedEventArg's GetDeferral method before starting async work in the NewWindowRequested event handler and call Complete on the Deferral once your async work is done in the NewWindowRequested event handler.

If you find cases where the WebView2 is opening new windows but the NewWindowRequested event isn't firing please open bugs at https://github.com/MicrosoftEdge/WebViewFeedback. What version of the SDK and the browser are you using with WebView2? There are some now fixed bugs with some scenarios opening new windows not firing the NewWindowRequested event.

David Risney
  • 3,886
  • 15
  • 16
  • Thanks David. Using this browser version - Version 86.0.571.0 (Official build) canary (64-bit) and SDK version - 3.1.201 – user1158993 Jul 09 '20 at 01:10
  • Please, could you elaborate more on how to obtain the reference to new window with example? Thanks a lot beforehand! – JohnyL Dec 01 '20 at 09:30