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


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM