對ExtendedWebBrowser的再擴展

<=======================
做者: 譚劍
關鍵字:C#,.NET,WebBrowser,ExtendedWebBrowser,瀏覽器,徹底載入,新窗口,腳本
=======================>
.NET 2.0 提供了一個新的WebBrowser控件.該WebBrowser控件爲咱們帶來了許多很是實用的新特性.舉個簡單的例子:
            HtmlDocument htmlDoc = webBrowser.Document;
            HtmlElement btnElement = htmlDoc.All["btnClose"];
            if (btnElement != null)
            {
                btnElement.click += new HtmlElementEventHandler(HtmlBtnClose_Click);
            }
僅需相似這樣簡單易懂的幾行代碼,即可實現Windows Forms對Web頁面各個HTML元素各類事件的響應.
在Windows Forms與Web頁面交互這方面,在功能與易用性上,該WebBrowser控件達到了一個史無前例的高度.這樣的特性,就已經爲咱們在進行相關的Windows Forms程序開發時選用它提供了足夠的理由.
很顯然,WebBrowser控件是對SHDocVw的AxWebBrowser這個非託管的ActiveX控件進行了封裝.可是在實用中,咱們很快能夠發現,其在提供新特性的同時,並無所有暴露出AxWebBrowser原有的屬性和方法,在不少狀況下,這樣就使得它顯得有點捉襟見肘了.
jlandheer對這個WebBrowser控件進行了擴展( 見Extended .NET 2.0 WebBrowser Control).可是該ExtendedWebBrowser也僅僅是提供了一個結構和思路,真正實現的擴展也比較有限.
根據實際的須要,我又對ExtendedWebBrowser進行了再擴展.
判斷頁面是否徹底載入:
1.新增DocumentCompleted事件:
在類ExtendedWebBrowser裏面事件部分的末尾添加以下代碼:
        public new event EventHandler<BrowserExtendedNavigatingEventArgs> DocumentCompleted;
        protected void OnDocumentCompleted(BrowserExtendedNavigatingEventArgs e)
        {
            if (e == null)
                throw new ArgumentNullException("e");
            if (this.DocumentCompleted != null)
                this.DocumentCompleted(this, e);
        }
2.實現public void DocumentComplete(object pDisp, ref object URL)方法:
 在文件ExtendedWebBrowser.cs class WebBrowserExtendedEvents : UnsafeNativeMethods.DWebBrowserEvents2 的 Unused events區域裏面能夠找到未實現的方法:
            public void DocumentComplete(object pDisp, ref object URL)
            {
            }
將其剪貼到已實現的方法部分的末尾,並修改成:
            public void DocumentComplete(object pDisp, ref object URL)
            {
                BrowserExtendedNavigatingEventArgs args = new BrowserExtendedNavigatingEventArgs(pDisp, new Uri(URL.ToString()), null, UrlContext.None);
                _Browser.OnDocumentCompleted(args);
            }
3.修改原有DocumentCompleted事件的響應:
因爲上面重寫了DocumentCompleted事件,因此須要修改原有的DocumentCompleted事件響應:
修改類BrowserControl中
            _browser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(_browser_DocumentCompleted);
爲:
            _browser.DocumentCompleted += new EventHandler<BrowserExtendedNavigatingEventArgs>(_browser_DocumentCompleted);
修改
        void _browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
爲:
        void _browser_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
其它相應的地方進行一樣的修改.
4.發送DocumentCompleted事件到最外層:
該ExtendedWebBrowser演示程序經過類WindowManager管理了一個標籤瀏覽器,若是須要,咱們能夠將事件發送到最外層,提供給MainForm使用.
將WindowManager中的代碼
        void WebBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
        {
            CheckCommandState();
        }
改爲:
        void WebBrowser_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
        {
            OnDocumentCompleted(sender, e);
            CheckCommandState();
        }
        public event EventHandler<BrowserExtendedNavigatingEventArgs> DocumentCompleted;
        /// <summary>
        /// Raises the DocumentCompleted event
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnDocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
        {
            if (DocumentCompleted != null)
                DocumentCompleted(sender, e);
        }
5.在須要的地方響應DocumentCompleted事件:
如:
            _windowManager.DocumentCompleted += new EventHandler<BrowserExtendedNavigatingEventArgs>(_windowManager_DocumentCompleted);
.
.
.
        void _windowManager_DocumentCompleted(object sender, BrowserExtendedNavigatingEventArgs e)
        {
            // 頁面徹底載入
            if (e.AutomationObject == ((ExtendedWebBrowser)sender).Application)
            {
                MessageBox.Show("DocumentCompleted:" + e.Url.ToString());
            }
        }
注意:必須e.AutomationObject == ((ExtendedWebBrowser)sender).Application才說明頁面已經徹底載入.因爲Web頁面可能爲多個框架嵌套的(可能還有其它的狀況,還沒有深究),那麼載入過程當中對應會有多個DocumentCompleted事件,而只有頁面徹底載入了,纔會e.AutomationObject == ((ExtendedWebBrowser)sender).Application.這就是爲何要費盡千辛萬苦把pDisp傳遞出來的緣由.
不彈出頁面,仍在當前瀏覽器瀏覽:
ExtendedWebBrowser中的StartNewWindow事件在彈出新頁面的時候觸發.其擴展的事件數據BrowserExtendedNavigatingEventArgs中已經提供了上下文,新頁面的URL,ppDisp等所需的數據.因此咱們只需改動類BrowserControl中的方法
        void _browser_StartNewWindow(object sender, BrowserExtendedNavigatingEventArgs e)
爲:
        void _browser_StartNewWindow(object sender, BrowserExtendedNavigatingEventArgs e)
        {
            // Here we do the pop-up blocker work
            // 這些彈出窗口過濾的代碼若是不須要,就所有刪除掉
            if (allowPopup)
            {
                // Check wheter it's a HTML dialog box. If so, allow the popup but do not open a new tab
                if (!((e.NavigationContext & UrlContext.HtmlDialog) == UrlContext.HtmlDialog))
                {
                    ExtendedWebBrowser ewb = mf.WindowManager.New(false);
                    // The (in)famous application object
                    e.AutomationObject = ewb.Application;
                }
            }
            //在這裏使用: e.AutomationObject = _browser.Application;彷佛沒有做用,
            //可是他原來的代碼e.AutomationObject = ewb.Application;是有用的(見上面註釋)
            //不知道是什麼緣由,只好暫時採用這個辦法
            _browser.Navigate(e.Url);
            e.Cancel = true;
        }
這裏若是使用e.AutomationObject = _browser.Application的話,彷佛同他原來的代碼e.AutomationObject = ewb.Application惟一的區別就是一個browser是瀏覽過頁面了的,一個browser.是新建的,難道會同這個有關? 哪位若是知道緣由,還請不吝賜教!
不彈出腳本錯誤提示框:
ExtendedWebBrowser經過響應事件WebBrowser.Document.Window.Error來捕獲腳本錯誤提示框彈出的消息:
        void _browser_DownloadComplete(object sender, EventArgs e)
        {
            // Check wheter the document is available (it should be)
            if (this.WebBrowser.Document != null)
            {
                // Subscribe to the Error event
                this.WebBrowser.Document.Window.Error += new HtmlElementErrorEventHandler(Window_Error);
.
.
.
        void Window_Error(object sender, HtmlElementErrorEventArgs e)
        {
            // We got a script error, record it
            ScriptErrorManager.Instance.RegisterScriptError(e.Url, e.Description, e.LineNumber);
            // Let the browser know we handled this error.
            e.Handled = true;
        }
可是彷佛仍是因爲前面提到的Web頁面存在多個框架嵌套的緣由,其可以捕獲到的消息比較有限,有很大一部分腳本錯誤提示消息仍然會捕獲不到.這樣一個問題困擾了我幾天.後來忽然發現ExtendedWebBrowser裏面有以下的代碼:
        /// <summary>
        /// This method supports the .NET Framework infrastructure and is not intended to be used directly from your code.  
        /// Called by the control when the underlying ActiveX control is created.  
        /// </summary>
        /// <param name="nativeActiveXObject"></param>
        [PermissionSet(SecurityAction.LinkDemand, Name = "FullTrust")]
        protected override void AttachInterfaces(object nativeActiveXObject)
        {
            this.axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
            base.AttachInterfaces(nativeActiveXObject);
        }
原來AxWebBrowser在這裏!因而簡單的設置了axIWebBrowser2.Silent屬性:
        protected override void AttachInterfaces(object nativeActiveXObject)
        {
            this.axIWebBrowser2 = (UnsafeNativeMethods.IWebBrowser2)nativeActiveXObject;
            this.axIWebBrowser2.Silent = true;//不彈腳本錯誤框
            base.AttachInterfaces(nativeActiveXObject);
        }
再也不彈出任何提示框,Silent屬性真的是恰如其名,整個世界清靜了...*^_^*
從上面的內容能夠看出,ExtendedWebBrowser截取了AxWebBrowser接口.那麼,不難想象,雖然個人"再擴展"只擴展瞭如上三項功能,其實咱們如今能夠作咱們任何想作的!
<=======================
做者: 譚劍
相關文章
相關標籤/搜索