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:231076364
需要的 qq 联系, 博客留言基本不看的. 加好友说明理由.
来源: https://blog.csdn.net/lanwilliam/article/details/79640954