最進想使用WPF+CefSharp實現瀏覽器多標簽頁, 所以直接實現ILifeSpanHandler接口添加窗口處理,但是在OnBeforePopup方法中,設置好窗口句柄后觸發彈出新頁時發現一個尷尬的問題:
問題
OnBeforePopup方法中調用SetAsPopup()方法,會導致瀏覽器首頁卡死(僅在WPF中發現,Winform不會),新窗口頁正常操作(后續窗口頁中都不會有這個問題)。
如果不調用SetAsPopup()方法,會導致新窗口頁的事件全部失效(處理器不會),比如TitleChanged事件在瀏覽器標題更改后,需要及時更新瀏覽器標題到控件上,這樣就無法觸發瀏覽器標題更改事件(TitleChanged)。
解決辦法
既然調用SetAsPopup會卡死,那我們就不調用,但是不調用SetAsPopup會導致新打開的窗口頁事件丟失,那就想辦法手動實現這個方法的一部分功能(賦值事件、處理器等信息)。
SetAsPopup方法中最后有一個out IWebBrowser newBrowser 參數,這個參數作用是新打開窗口頁的瀏覽器對象需不需要我們提供,一般設置這個參數為null,不需要我們提供。
如果不為null時,新窗口瀏覽器對象將使用newBrowser作為新窗口頁的瀏覽器對象。
public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess,
out IWebBrowser newBrowser) {
所以在方法中顯示給newBrowser賦上值,(相當於實現一部分SetAsPopup方法工作...):
public class CefLifeSpanHandler : ILifeSpanHandler { //省略其他ILifeSpanHandler接口實現方法...
//構造函數傳入窗口對象,方便控制窗口中的控件 MainWindow mainWindow; public CefLifeSpanHandler(MainWindow _mainWindow) { this.mainWindow = _mainWindow; } //瀏覽器新窗口彈出時調用方法 public bool OnBeforePopup(IWebBrowser chromiumWebBrowser, IBrowser browser, IFrame frame, string targetUrl, string targetFrameName, WindowOpenDisposition targetDisposition, bool userGesture, IPopupFeatures popupFeatures, IWindowInfo windowInfo, IBrowserSettings browserSettings, ref bool noJavascriptAccess, out IWebBrowser newBrowser) { //為新彈窗創建一個瀏覽器對象 ChromiumWebBrowser newChromeBrowser = new ChromiumWebBrowser(); //為新彈窗復制窗口處理 newBrowser.LifeSpanHandler = this; //省略賦值其他處理器... //賦值標題修改事件 newChromeBrowser.TitleChanged += mainWindow.Chrome_TitleChange; //省略賦值其他事件.... //留下創建的瀏覽器對象引用,windowList(List<ChromiumWebBrowser>)是在MainWindow下聲明的變量,窗口關閉時要釋放,不然退出程序會跨線程訪問控件錯誤 mainWindow.windowList.Add(newChromeBrowser); //為瀏覽器賦值 newBrowser = newChromeBrowser; //.... return false; } }
到這里,在新窗口頁打開時,即觸發了標題修改事件,又沒有導致瀏覽器首頁卡死,但在關閉窗口時,會報跨線程訪問錯誤,需要在窗口關閉時釋放掉創建的窗口瀏覽器對象:
private void Window_Closed(object sender, EventArgs e) { //釋放每一個chrome窗口資源 for (int i = 0; i < windowList.Count; i ++) { windowList[i].Dispatcher.Invoke(delegate { windowList[i].Dispose(); }); } }
到這里,基本上解決了阻止瀏覽器彈窗時調用 SetAsPopup 首頁卡死問題。
如果本人有理解不對的地方,希望前輩們評論區指導,非常感謝!