本文内容由阿里云实名注册用户自发贡献,版权归原作者所有,阿里云开发者社区不拥有其著作权,亦不承担相应法律责任。具体规则请查看《 阿里云开发者社区用户服务协议 》和 《 阿里云开发者社区知识产权保护指引 》。如果您发现本社区中有涉嫌抄袭的内容,填写 侵权投诉表单 进行举报,一经查实,本社区将立刻删除涉嫌侵权内容。

CefSharp的Browser怎么说也是嵌入了Chromium的浏览器,所以碰到<a >标签“_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的必要功能就全了,可以应用了。

希望对大家有帮助。

抱歉,没想到加QQ好友的这么多,暂时不接受好友申请了,上限了。大家 还是留言吧。