原文: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 的必要功能就全了,可以應用了。