熙熙-WebBrowser判断登录成功-WebBrowser-404错误-500错误-屏蔽消息窗口-Webbrowser判断是否加载成功

在这里,我来讲讲怎么应付WebBrowser里面的那点破事:

文档真的完成了吗?

也许你和我一样,打开一个页面,听到了不少次的哒哒哒哒的声音,但是单个页面怎么会造成多次的触发DocumentCompleted函数?不信自己试试,判断文档是否真的完成,需要在这个处理函数内判断ReadyState如下:

private void WebBrowserEx_DocumentCompleted(object sender
            , WebBrowserDocumentCompletedEventArgs e)
        {
            if (this.ReadyState == WebBrowserReadyState.Complete)
            {
                if (null != this.Document && null != this.OnDocumentCompleted)
                {
                    this.OnDocumentCompleted(sender, e);
                }
            }
        }

404错误怎么办?500错误怎么办?

正如你所猜测的,即便是页面浏览错了,在页面中还是会显示内容,还是会无耻的触发DocumentCompleted事件,那么怎么判断到底是404页面还是500页面呢?看招:

SHDocVw.WebBrowser sw = this.ActiveXInstance as SHDocVw.WebBrowser;
sw.NavigateError += sw_NavigateError;
//-----------------------------------------
 void sw_NavigateError(object pDisp, ref object URL, ref object Frame
    , ref object StatusCode, ref bool Cancel)
{
    ErrorCodes errorcode = ErrorCodes.HTTP_STATUS_BAD_REQUEST;
    foreach (ErrorCodes ecode in Enum.GetValues(typeof(ErrorCodes)))
    {
        if (((long)ecode) == (Int32)StatusCode)
        {
            errorcode = ecode;
            break;
        }
    }
    System.Console.WriteLine("Error " + URL + ">>" + errorcode);
}

上面的代码中存在一个很丑陋的转换Enum的操作,我懒得修改了,这个枚举是俺自己定义的,定义的就是错误的名字信息,如下:

   1:  publicenumErrorCodes:long
   2:  {
   3:  HTTP_STATUS_BAD_REQUEST=400,
   4:  HTTP_STATUS_DENIED=401,
   5:  HTTP_STATUS_PAYMENT_REQ=402,
   6:  HTTP_STATUS_FORBIDDEN=403,
   7:  HTTP_STATUS_NOT_FOUND=404,
   8:  HTTP_STATUS_BAD_METHOD=405,
   9:  HTTP_STATUS_NONE_ACCEPTABLE=406,
  10:  HTTP_STATUS_PROXY_AUTH_REQ=407,
  11:  HTTP_STATUS_REQUEST_TIMEOUT=408,
  12:  HTTP_STATUS_CONFLICT=409,
  13:  HTTP_STATUS_GONE=410,
  14:  HTTP_STATUS_LENGTH_REQUIRED=411,
  15:  HTTP_STATUS_PRECOND_FAILED=412,
  16:  HTTP_STATUS_REQUEST_TOO_LARGE=413,
  17:  HTTP_STATUS_URI_TOO_LONG=414,
  18:  HTTP_STATUS_UNSUPPORTED_MEDIA=415,
  19:  HTTP_STATUS_RETRY_WITH=449,
  20:  HTTP_STATUS_SERVER_ERROR=500,
  21:  HTTP_STATUS_NOT_SUPPORTED=501,
  22:  HTTP_STATUS_BAD_GATEWAY=502,
  23:  HTTP_STATUS_SERVICE_UNAVAIL=503,
  24:  HTTP_STATUS_GATEWAY_TIMEOUT=504,
  25:  HTTP_STATUS_VERSION_NOT_SUP=505,
  26:   
  27:  INET_E_INVALID_URL=0x800C0002L,
  28:  INET_E_NO_SESSION=0x800C0003L,
  29:  INET_E_CANNOT_CONNECT=0x800C0004L,
  30:  INET_E_RESOURCE_NOT_FOUND=0x800C0005L,
  31:  INET_E_OBJECT_NOT_FOUND=0x800C0006L,
  32:  INET_E_DATA_NOT_AVAILABLE=0x800C0007L,
  33:  INET_E_DOWNLOAD_FAILURE=0x800C0008L,
  34:  INET_E_AUTHENTICATION_REQUIRED=0x800C0009L,
  35:  INET_E_NO_VALID_MEDIA=0x800C000AL,
  36:  INET_E_CONNECTION_TIMEOUT=0x800C000BL,
  37:  INET_E_INVALID_REQUEST=0x800C000CL,
  38:  INET_E_UNKNOWN_PROTOCOL=0x800C000DL,
  39:  INET_E_SECURITY_PROBLEM=0x800C000EL,
  40:  INET_E_CANNOT_LOAD_DATA=0x800C000FL,
  41:  INET_E_CANNOT_INSTANTIATE_OBJECT=0x800C0010L,
  42:  INET_E_REDIRECT_FAILED=0x800C0014L,
  43:  INET_E_REDIRECT_TO_DIR=0x800C0015L,
  44:  INET_E_CANNOT_LOCK_REQUEST=0x800C0016L,
  45:  INET_E_USE_EXTEND_BINDING=0x800C0017L,
  46:  INET_E_TERMINATED_BIND=0x800C0018L,
  47:  INET_E_INVALID_CERTIFICATE=0x800C0019L,
  48:  INET_E_CODE_DOWNLOAD_DECLINED=0x800C0100L,
  49:  INET_E_RESULT_DISPATCHED=0x800C0200L,
  50:  INET_E_CANNOT_REPLACE_SFP_FILE=0x800C0300L,
  51:  INET_E_CODE_INSTALL_BLOCKED_BY_HASH_POLICY=0x800C0500L,
  52:  INET_E_CODE_INSTALL_SUPPRESSED=0x800C0400L,
  53:  }

Winform的WebBrowser居然不自己定义错误值,真是一个半成品啊。

让内部的Html调用的JS可以使用外部提供的C#类的函数

做起来简单。首先生成一个类(第一行不能少)

[System.Runtime.InteropServices.ComVisibleAttribute(true)]
public class A
{
    public String Fun()
    {
        return Guid.NewGuid().ToString();
    }
}

构造WebBrowser的时候设置属性 ObjectForScripting=new A();

页面中使用类似如下的代码(注意函数名为window.external):

<a href="javascript:{alert(window.external.Fun());}">测试按钮</a>

赶紧试试吧

事件调用转换成过程调用

需求是这样的,我需要做一个模拟的操作界面,包括:登录,打开特定页面,填写内容,提交几步。在事件模型之下,我需要先调用Navigate函数, 然后在DocumentCompleted的处理函数中处理每个的返回内容,这样很麻烦,能不能使用一个函数将事件处理直接屏蔽掉 (SynchronizedNavigate),我的操作转换成:

  1. SynchronizedNavigate(登录页面)
  2. 填写登录信息
  3. 模拟点击登录按钮
  4. SynchronizedNavigate(数据填充页面)
  5. 填写页面内容
  6. 提交到服务器
  7. 取得返回页面校验实际输入的值

是不是很玄妙,其实很简单(注意不能缺少函数Application.DoEvents())

   1:  public void SynchronizedNavigate(String strUrl)
   2:  {
   3:      this.Navigate(strUrl);
   4:      WaitNavigatingDone();
   5:  }
   6:   
   7:  public void WaitNavigatingDone()
   8:  {
   9:      while (m_isDocumentationCompleted == false)
  10:      {
  11:          Application.DoEvents();
  12:          Thread.Sleep(50);
  13:      }
  14:  }

怎么屏蔽内部的消息窗口?

直接看代码,很无耻滴注册了函数进去

private void WebBrowserEx_Navigated(object sender, WebBrowserNavigatedEventArgs e)
        {
            if (this.Document == null || this.Document.DomDocument == null)
            {
                return;
            }
            mshtml.IHTMLDocument2 doc2 = this.Document.DomDocument as mshtml.IHTMLDocument2;
            if (this.BlockClientMessage)
            {
                if (null != doc2 && null != doc2.parentWindow)
                {
                    //block alert and confirm
                    doc2.parentWindow.execScript(@"function alert(){} function confirm(){return true;}"
                        , "javaScript");
                }
 
            }
        }

怎么屏蔽网页内部弹出内容到新窗口?

也许你可以使用Navigate的变种,里面有void Navigate(string urlString, bool newWindow)和Navigate(Uri url, bool newWindow)这两个函数,俺没有仔细试过,我使用的是COM接口:

this.Navigate("about:blank");
SHDocVw.WebBrowser sw = this.ActiveXInstance as SHDocVw.WebBrowser;
if (null != sw)
{
    sw.NewWindow3 += new SHDocVw.DWebBrowserEvents2_NewWindow3EventHandler(sw_NewWindow3);
}
----------------------
 void sw_NewWindow3(ref object ppDisp, ref bool Cancel, uint dwFlags, string bstrUrlContext, string bstrUrl)
 {
     if (null == OnNewWindow && this.BlockPopWindow)
     {
         Cancel = true;
         this.Navigate(bstrUrl);
     }
     else if (null != OnNewWindow)
     {
         OnNewWindow(this, bstrUrl, ref Cancel);
     }
 }

自定义协议?

你是不是想玩玩在<a href=”personal://username=1235”>用户信息</a>的点击的时候弹出一个内部的页面,而不是默认的 Http访问?实现类似的协议很简单,在_Navigating(object sender, WebBrowserNavigatingEventArgs e)这个事件处理中处理即可:当碰到您的协议的时候,e.Cancel=true;然后生成HTML,设置DocumentText就完成了。

取得当前的选择的文本

 public string SelectedText
{
    get
    {
        IHTMLDocument2 doc = (IHTMLDocument2)this.Document.DomDocument;
        IHTMLTxtRange txt = (IHTMLTxtRange)doc.selection.createRange();
        return txt.htmlText;
    }
}

高亮指定的文本

   1:   public void HilightText(string keyword, int nindexK)
   2:          {
   3:              if (null == keyword ||
   4:                  keyword.Trim().Length < 1 ||
   5:                  null == this.Document ||
   6:                  this.Document.DomDocument == null ||
   7:                  this.IsBusy ||
   8:                  this.IsDisposed
   9:                  )
  10:              {
  11:                  return;
  12:              }
  13:              HTMLDocument document = (HTMLDocument)this.Document.DomDocument;
  14:              IHTMLDOMNode bodyNode = (IHTMLDOMNode)this.Document.Body.DomElement;
  15:              HilightText(document, bodyNode, keyword.Trim(), nindexK);
  16:          }
  17:   
  18:          private void HilightText(HTMLDocument document, IHTMLDOMNode node, string keyword, int nindexK)
  19:          {
  20:              // nodeType = 3:text节点
  21:              if (node.nodeType == 3)
  22:              {
  23:                  string nodeText = node.nodeValue.ToString();
  24:                  // 如果找到了关键字
  25:                  if (nodeText.Contains(keyword))
  26:                  {
  27:                      IHTMLDOMNode parentNode = node.parentNode;
  28:                      // 将关键字作为分隔符,将文本分离,并逐个添加到原text节点的父节点
  29:                      string[] result = nodeText.Split(new string[] { keyword }, StringSplitOptions.None);
  30:                      for (int i = 0; i < result.Length - 1; i++)
  31:                      {
  32:                          if (result[i] != "")
  33:                          {
  34:                              IHTMLDOMNode txtNode = document.createTextNode(result[i]);
  35:                              parentNode.insertBefore(txtNode, node);
  36:                          }
  37:                          IHTMLDOMNode orgNode = document.createTextNode(keyword);
  38:                          IHTMLDOMNode hilightedNode = (IHTMLDOMNode)document.createElement("SPAN");
  39:                          IHTMLStyle style = ((IHTMLElement)hilightedNode).style;
  40:                          style.color = "black";
  41:                          style.backgroundColor = colorTables[nindexK % colorTables.Length];
  42:                          hilightedNode.appendChild(orgNode);
  43:   
  44:                          parentNode.insertBefore(hilightedNode, node);
  45:                      }
  46:                      if (result[result.Length - 1] != "")
  47:                      {
  48:                          IHTMLDOMNode postNode = document.createTextNode(result[result.Length - 1]);
  49:                          parentNode.insertBefore(postNode, node);
  50:                      }
  51:                      parentNode.removeChild(node);
  52:                  } // End of nodeText.Contains(keyword)
  53:              }
  54:              else
  55:              {
  56:                  // 如果不是text节点,则递归搜索其子节点
  57:                  IHTMLDOMChildrenCollection childNodes = node.childNodes as IHTMLDOMChildrenCollection;
  58:                  foreach (IHTMLDOMNode n in childNodes)
  59:                  {
  60:                      HilightText(document, n, keyword, nindexK);
  61:                  }
  62:              }
  63:          }

posted on 2011-06-24 21:11  桂林熙熙  阅读(5951)  评论(3编辑  收藏  举报

导航

收录查询