• 判断页面是否完全载入对ExtendedWebBrowser的DocumentCompleted再扩展


    .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接口.那么,不难想象,虽然我的"再扩展"只扩展了如上三项功能,其实我们现在可以做我们任何想做的!

  • 相关阅读:
    label 选择: soft label or hard label?
    预训练模型 | MASS:更适合seq2seq类任务
    文本相似度计算/文本比较算法
    论文阅读 | Is BERT Really Robust? A Strong Baseline for Natural Language Attack on Text Classification and Entailment
    论文阅读 | Lite Transformer with Long-Short Range Attention
    预训练模型 | ELECTRA: Efficiently Learning an Encoder that Classifies Token Replacements Accurately
    Transformer 及其家族( Transformer-XL, Reformer... )
    java线程池01-ThreadPoolExecutor构造方法参数的使用规则
    快速排序算法
    mysql(4)—— 表连接查询与where后使用子查询的性能分析。
  • 原文地址:https://www.cnblogs.com/sung/p/2854223.html
Copyright © 2020-2023  润新知