CefSharp 中 ChromiumWebBrowser 打开新页面处理 拦截弹出窗口

原文:https://blog.csdn.net/lanwilliam/article/details/79640954

CefSharp 的 Browser 怎么说也是嵌入了 Chromium 的浏览器,所以碰到 标签 “_blank” 这样的时候,都是弹出新窗体打开新页面。

但是怎奈我使用了 DevExpress 控件中的 TabForm 这个东西来作为主窗体,所以我不希望弹出新的窗体来,那么就需要捕获打开新窗体这样一个事件来重写了。

但是你会发现,在 ChromiumWebBrowser 对象中,没有 OnNewWindow 这类的事件啊,怎么办,难道到此为止了吗?!

果然百度还是无能为力,找 google 查了一下。CefSharp 通过另一个对象处理的这类事件。CefLifeSpanHandler,就是这个东西了。里面提供了我们要用的事件,不废话,上代码。

    public class CefLifeSpanHandler : CefSharp.ILifeSpanHandler
    {
        public CefLifeSpanHandler()
        {
 
        }
 
        public bool DoClose(IWebBrowser browserControl, CefSharp.IBrowser browser)
        {
            if (browser.IsDisposed || browser.IsPopup)
            {
                return false;
            }
 
            return true;
        }
 
        public void OnAfterCreated(IWebBrowser browserControl, IBrowser browser)
        {
 
        }
 
        public void OnBeforeClose(IWebBrowser browserControl, IBrowser browser)
        {
        }
        
 
        public bool OnBeforePopup(IWebBrowser browserControl, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser)
        {
            var chromiumWebBrowser = (ExtChromiumBrowser)browserControl;
 
            chromiumWebBrowser.Invoke(new Action(() =>
            {
                NewWindowEventArgs e = new NewWindowEventArgs(windowInfo, targetUrl);
                chromiumWebBrowser.OnNewWindow(e);
            }));
 
            newBrowser = null;
            return true;
        }
    }

这是 Handler 的实现。

然后需要封装一下 ChromiumWebBrowser,提供 OnNewWindow 事件。

    public class ExtChromiumBrowser : ChromiumWebBrowser
    {
        public ExtChromiumBrowser()
            : base(null)
        {
            this.LifeSpanHandler = new CefLifeSpanHandler();
            //this.DownloadHandler = new DownloadHandler(this);
        }
 
        public ExtChromiumBrowser(string url) : base(url)
        {
            this.LifeSpanHandler = new CefLifeSpanHandler();
        }
 
        public event EventHandler<NewWindowEventArgs> StartNewWindow;
 
        public void OnNewWindow(NewWindowEventArgs e)
        {
            if (StartNewWindow != null)
            {
                StartNewWindow(this, e);
            }
        }
    }

含有事件参数定义

    public class NewWindowEventArgs : EventArgs
    {
        private IWindowInfo _windowInfo;
        public IWindowInfo WindowInfo
        {
            get { return _windowInfo; }
            set { value = _windowInfo; }
        }
        public string url { get; set; }
        public NewWindowEventArgs(IWindowInfo windowInfo, string url)
        {
            _windowInfo = windowInfo;
            this.url = url;
        }
    }

然后我们用新定义的 ExtChromiumBrowser 替换之前的 ChromiumWebBrowser,并且实现相关代码。

        public void InitBrowser()
        {
            Cef.Initialize(new CefSettings());
            browser = new ExtChromiumBrowser("http://124.128.61.90:10080/login.html");
            //this.Controls.Add(browser);
            tabFormContentContainer1.Controls.Add(browser);
            browser.Dock = DockStyle.Fill;
            browser.StartNewWindow += Browser_StartNewWindow;
            browser.TitleChanged += OnBrowserTitleChanged;
            browser.FrameLoadEnd += browser_FrameLoadEnd;
            CefSharpSettings.LegacyJavascriptBindingEnabled = true;
            browser.RegisterJsObject("jsObj", new SendCarBillPrint());
            //browser.JavascriptObjectRepository.Register("jsObj", new SendCarBillPrint(), false);
        }

然后是 StartNewWindow 的事件实现。

        private void Browser_StartNewWindow(object sender, NewWindowEventArgs e)
        {
            TabFormPage tp = new TabFormPage();
            tp.Text = "新窗口";
            TabFormContentContainer tc1 = new TabFormContentContainer();
            tp.ContentContainer = tc1;
            tc1.Dock = DockStyle.Fill;
            var control = new ExtChromiumBrowser(e.url);
            control.Dock = DockStyle.Fill;
            //control.CreateControl();
            //host.Child = control;
            control.Focus();
 
            tc1.Controls.Add(control);
            tabFormControl1.Pages.Add(tp);
            tabFormControl1.SelectedPage = tp;
            tp.Text = control.Text;
            control.StartNewWindow += Browser_StartNewWindow;
            control.TitleChanged += OnBrowserTitleChanged;
            //e.WindowInfo.SetAsChild(control.Handle, 0, 0, (int)host.ActualWidth, (int)host.ActualHeight);
        }

这样就实现了拦截打开窗口事件,并且在新 tab 中打开了。

需要注意的是,OnBeforePopup 事件中,return true 后,ChromiumWebBrowser 就不会再打开新窗口了。我这里手动创建了新的 Tab 页,然后添加了 Browser,然后将拦截的 url 设置上去,实现了新 tab 的显示。但其实这样做并非最优,我这里是为解决 DevExpress 的 Tab 窗体控件问题才这么搞的。

注意看我之前注释的代码。

e.WindowInfo.SetAsChild(control.Handle, 0, 0, (int)host.ActualWidth, (int)host.ActualHeight);

其实这才是正确的办法。

在 OnBeforePopup 事件中返回 false。然后在 Browser_StartNewWindow 事件中,通过上面 SetAsChild 方法设置才是好的办法。原理是将新打开窗体的设置到 Control.Handle 上去了。Control 可以是个窗体,也可以是个 Panel 之类的 Control,设置好大小。这样原则上只开了一个 Browser 对象。道理上应该性能好一点。

但是,注意了,但是,我本来想优化一下来着,发现在 windows 任务管理器中,其实也是两个进程,加上 DevExpress 好多资料不好找,于是就先这样了。有空再说吧。

至此,基本上 Winform 嵌入 ChromiumWebBrowser 的必要功能就全了,可以应用了。

CefSharp 中 ChromiumWebBrowser 打开新页面处理 拦截弹出窗口

上一篇:Flume—FLume安装步骤


下一篇:css--垂直水平居中