【问题标题】:Create tabs using WebView2 - Edge使用 WebView2 - Edge 创建选项卡
【发布时间】:2020-07-08 16:39:53
【问题描述】:

请提供代码 sn-p 以在单击 webview2 - C# windows 窗体中的 Edge 中的链接时创建选项卡而不是在新窗口中打开页面。

按照以下步骤操作。

  1. 在C# windows窗体上拖动webview2控件并更新源属性链接:https://example.com

  2. https://example.com站点在webview2中打开成功

  3. 点击网站中的几个链接 - https://example.com 并打开新窗口并寻找在新标签中打开这个而不是在新窗口中打开

  4. 调试代码时,此事件 webView.CoreWebView2.NewWindowRequested 从未发生过。如果引发此 webView.CoreWebView2.NewWindowRequested 事件,则 webview 类上没有导航方法可用,并且在 corewebview2 类上可用,如果我们使用它,则会出现空引用异常。

【问题讨论】:

  • 到底是什么问题?
  • 如果我们点击通过 WebView2 打开的网站中的链接(目标=_blank 的锚标记),并且链接正在新的 webview 窗口中打开。需要创建一个程序来在选项卡中显示链接页面。
  • 我赞成戴维斯的观点。您需要创建自己的 UI 以在选项卡中打开链接。 WebView2 中没有对此的支持。我们可以处理New­Window­Requested 事件来防止打开浏览器窗口。你可以参考this article。如果无法触发事件,您可以提供最少的代码来重现问题,以便我们进行测试。此外,this sample 展示了如何在 webview2 中使用选项卡,但它使用的是 c++。

标签: c# microsoft-edge winforms-to-web webview2


【解决方案1】:

为了完整起见,感谢 David Risney 的解释,我能够实现相同的目标。不幸的是,它没有包含任何代码,但我使用1.0.721-prereleaseMicrosoft.WebView2.FixedVersionRuntime.87.0.664.66.x64 实现了这一点:

程序.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');");
        }
    }
}

所以它的工作方式有点奇怪:要生成一个新窗口,您可以通过 JavaScript 使用 ExecuteScriptAsync 来实现。在这种情况下,我将打开一个新窗口到 bing.com。所以,这会打电话给CoreWebView2_NewWindowRequested。为了让事件通过并且代码可以工作(否则它会冻结),它必须经历这一切。因此,您不能在当前正在发生的事件中设置 CoreWebView2NewWindowRequestedEventArgsNewWindow 属性。

解决方案是将事件数据(args 和 deferral)带到新表单中,显示它,并在加载和 之后 控件的 CoreWebView2 属性不为空 / 已初始化,通过调用CoreWebView2InitializationCompleted,检查args/deferral 是否不为null,然后将defer 调用为Complete()(这基本上就像一个JS 承诺)AND 在这里你可以设置NewWindow 属性因为CoreWebView2 已经初始化,所以它不为空。

希望这将回答您的问题和未来的读者。有了这段代码,我就可以让它工作了。

【讨论】:

  • 只是查看所有 NewWindowRequested 问题。无论 newwindowrequested 事件中的 uri 是什么,您的上述代码是否总是导航到 Google?
  • 打开的第一个实例,是的。第二个是由 window.open() 产生的,它反过来触发 NewWindowRequested 事件,其 URL 已设置为 bing.com。如果你想改变,你可以通过在我认为的 defer() 之后设置 Url 属性。
  • 好的,谢谢,我现在看到了。 load 事件将在新表单的浏览器事件初始化触发之前触发。
【解决方案2】:

WebView2 中没有内置的选项卡支持。但是,您可以使用 NewWindowRequested 事件拦截新窗口,并提供您自己的 CoreWebView2 作为该新窗口,然后将 CoreWebView2 按您喜欢的方式放置在 UI 中。例如,可以将新的 CoreWebView2 放置在您的 UI 中,使其看起来像一个新选项卡。 (听起来这就是你正在做的事情,但在这里明确声明只是为了确保我正确理解你的场景。)

关于为空的 WebView2.CoreWebView2 属性,您可以调用EnsureCoreWebView2Async 并等待返回的任务,或者您可以设置 WebView2.Source 属性并等待CoreWebView2Ready event 调度以便 WebView2.CoreWebView2 属性填写。在此之前为空。

另外,如果您需要获取CoreWebView2填写NewWindowRequestedEventArg's NewWindow property,由于上述从WebView2实例获取CoreWebView2的步骤都是异步的,您需要在开始异步工作之前调用NewWindowRequestedEventArg's GetDeferral method在 NewWindowRequested 事件处理程序中,并在 NewWindowRequested 事件处理程序中完成异步工作后在 Deferral 上调用 Complete。

如果您发现 WebView2 正在打开新窗口但 NewWindowRequested 事件未触发的情况,请在 https://github.com/MicrosoftEdge/WebViewFeedback 处打开错误。您在 WebView2 中使用什么版本的 SDK 和浏览器?现在修复了一些错误,在某些情况下打开新窗口不会触发 NewWindowRequested 事件。

【讨论】:

  • 谢谢大卫。使用此浏览器版本 - 版本 86.0.571.0(官方构建)金丝雀(64 位)和 SDK 版本 - 3.1.201
  • 请您详细说明如何通过示例获取对新窗口的引用?提前非常感谢! ?
猜你喜欢
  • 2018-03-04
  • 2020-10-31
  • 1970-01-01
  • 2012-09-29
  • 2012-10-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多