• 【Winform 控件浅谈 】 之 WebBrowser


    前言

    鄙人才疏学浅,如果说错了,还请各位不吝赐教

    1.什么是 WebBrowser

    下面是已有的轮子,我想说它们是专业的

    http://baike.baidu.com/view/2981935.htm?fr=aladdin

    http://msdn.microsoft.com/zh-cn/library/system.windows.forms.webbrowser(v=vs.110).aspx

    技巧

    http://www.cnblogs.com/c51port/archive/2011/06/24/2089350.html

    http://www.cnblogs.com/sufei/p/3160340.html

    2.用它做什么

    除了可以访问/操作网页,或者是作为数据采集一种方案,我知识有限,难想到它还能干什么,欢迎指教

    很多人肯定知道,采集应该用HttpWebRequest,或者什么 WebClient之类的,那个效率要高很多

    确实,HttpWebRequest效率确实高很多,因为它请求一个Web Url 获取的都是Html字符串,不会加载你采集数据基本上用不上的东西

    但是如果想做简单的Web Url客户端模拟,我觉得这个还是有他的用武之地的,为什么这么说,因为它会加载js啊,然后就没有然后了.

    3.怎么用

    1.拖/new

    2.绑定事件

    3.在事件里处理动作

     详细内容请在本文后下载/查看源代码

    4.一点扩展,什么是闭包,C#闭包

    1.什么是闭包

    闭包一词经常在 Javascript 里面出现

    根据名字来看可以简单解释,封闭的包,简单来说就是一个匿名函数,在这个函数里可以定义变量,外部无法访问,可以用来延长外部变量的作用时间

    2.C#闭包

            /// <summary>
            /// 进度条最大值
            /// </summary>
            public const string P_MAX = "Maximum";
    
            /// <summary>
            /// 进度条当前值
            /// </summary>
            public const string P_VALUE = "Value";
    
            /// <summary>
            /// 设置进度条相关参数
            /// </summary>
            /// <param name="p">进度条</param>
            /// <param name="property"></param>
            /// <param name="value"></param>
            /// <returns></returns>
            public static bool SetProgress(object p, string property, object value)
            {
                if (p != null && (p is ToolStripProgressBar || p is ProgressBar))
                {
                    Type type = p.GetType();
                    type.GetProperty(property).SetValue(p, value);
                    return true;
                }
                return false;
            }
    
            /// <summary>
            /// 链接调用
            /// 用于做返回值为boolean函数链接调用
            /// </summary> 
            public static void R(bool b){ }
    
            /// <summary>
            /// 绑定WebBrowser动作
            /// </summary>
            /// <param name="w">WebBrowser</param>
            /// <param name="ps">任务列表</param>
            /// <param name="ctrl">进度条</param>
            public static void xBinding(this W w, List<PageObject> pos,object ctrl = null)
            {
                if (pos == null || pos.Count == 0) return;  
    
                SetProgress(ctrl, P_MAX, pos.Count);
                for (int i = 0, l = pos.Count; i < l; i++)
                {
                    w.DocumentCompleted += new Func<int, PageObject, WebBrowserDocumentCompletedEventHandler>((v , o) => {
                        return (s , e) => R(o.DoAction(s as W) && SetProgress(ctrl, P_VALUE, v + 1));
                    })(i, pos[i]); 
                }
            }
    
        /// <summary>
        /// 页面处理对象
        /// </summary>
        public class PageObject
        {
            /// <summary>
            /// 监听Url
            /// </summary>
            public string Url
            {
                get;
                set;
            }
    
            /// <summary>
            /// 当前地址动作
            /// </summary>
            public Action<W> Action
            {
                get;
                set;
            }
    
            /// <summary>
            /// 构造
            /// </summary>
            /// <param name="url"></param>
            /// <param name="action"></param>
            public PageObject(string url, Action<W> action)
            {
                this.Url = url;
                this.Action = action;
            }
    
            /// <summary>
            /// 触发地址动作
            /// 如果WebBrowser地址和需要匹配的地址一致就做当前的动作
            /// </summary>
            /// <param name="w"></param>
            public bool DoAction(W w)
            {
                if (w != null && w.xIsReady() && w.xIsUrl(this.Url))
                {
                    this.Action(w);
                    return true;
                }
                return false;
            }
        }
    PageObject.cs

    上面如果直接 += new WebBrowserDocumentCompletedEventHandler 不用闭包的话,就会出现WebBrowser每次触发DocumentCompleted事件的时候,

    如果在WebBrowserDocumentCompletedEventHandler 里面引用了 i ,那么i 会一直都是 pageObjects.Count - 1

    5.一点思考,怎么用

    实际上说这个我比较心虚,因为我用的时候都是在DocumentCompleted处理网页里面的内容

    我不知道是否有更好的方法来做网页加载完后的事情

    而且最让我烦恼的是代码看上去实在不敢恭维,如果我的DocumentCompleted里面要多个页面间的事情,我就得拼命的if else

    这是一件让代码很不愉快的事情,代码都不愉快了,我还怎么和它做朋友呢

    然,然,然后,不管你怎么写,我反正是这么写了

            private const string U_BD = "http://www.baidu.com/";
            private const string U_CB = "http://www.cnblogs.com/";
            private const string U_IQ = "http://www.infoq.com/cn/";
            private const string U_CD = "http://www.csdn.net/";
            private const string U_MS = "http://msdn.microsoft.com/zh-CN/";
            private const string U_CT = "http://www.51cto.com/";
            private const string U_TB = "http://www.taobao.com";
    
            private void frmWebBrowser_Load(object sender, EventArgs e)
            {
                List<PageObject> task = new List<PageObject>()
                {
                   new PageObject(U_BD,(w)=>{ w.Navigate(U_CB); }), 
                   new PageObject(U_CB,(w)=>{ w.Navigate(U_IQ); }), 
                   new PageObject(U_IQ,(w)=>{ w.Navigate(U_CD); }), 
                   new PageObject(U_CD,(w)=>{ w.Navigate(U_MS); }), 
                   new PageObject(U_MS,(w)=>{ w.Navigate(U_CT); }), 
                   new PageObject(U_CT,(w)=>{
                       w.xExecScript(@" var urlString = window.location;
                                        function showUrl(a){
                                            alert( urlString + ' 这个地址是最后一个任务,5秒后将进入 about:blank '+a);
                                            setTimeout(function(){ window.location='about:blank';},5000);                                
                                        }
                                        showUrl('abc');"); 
                   }), 
                };
                webMain.xBinding(task, progressAccessRate);
                webMain.Navigate(U_BD);
            }

    6.结语

    WebBrowser有关的内容差不多我知道的就这些了

    还有一个事情我忘记说了,就是在WebBrowser里面你也许想调用下自己的javascript 函数,或者网页里面的函数

    但是 WebBrowser.Document 只有一个InvokeScript,这个不是那么灵活,可能是因为我道行还不够吧

    虽然示例很多时候是这样的 WebBrowser.Document.InvokeScript("alert",new object[]{ "abc" });

    听说可以直接这样使用WebBrowser.Document.InvokeScript("return false");

    或者这样试试

            /// <summary>
            /// 执行脚本
            /// 请置于WebBrowser.DocumentCompleted 事件里执行,防止调用的内容未加载完
            /// </summary>
            /// <param name="w">需要执行脚本的WebBrowser对象</param>
            /// <param name="js">脚本</param>
            public static void xExecScript(this W w, string js)
            {
                w.Document.InvokeScript("eval", new object[] { "(function(){ "+js+"}());" });
            }

    这样写后你就可以参考本文第5部分来实现自己的动作

    你以为完了吗,不,还要等等,让我在啰嗦两句

    网页加载完可能不是真的加载完了,也许你需要先检查 这个WebBrowser对象的ReadyState 就像这样

    if(w.ReadyState == WebBrowserReadyState.Complete) {
        .... 
    }

    7.下载

    https://files.cnblogs.com/lxmyn/MSolution.Stu.Win.WebBrowser.rar

    这个是用VS2012开发的,当然我使用的是盗版,对此我深感愧疚

    如果你的VS版本低那么一点点或高一点,你也许可以,通过修改.csproj文件来打开项目

    如果你的低太多,你也许得自己新建一个工程,然后把代码考进去,删除掉多余的using,以及自己手写替换掉不兼容的代码

    8.知识扩展

    事实上,虽然WebBrowser在大多数情况下已经能够满足我们日常的要求,当然我也很希望是这样的

    也许有一天,你发现,你用真实的Web浏览器和用WebBrowser访问的不一致的时候

    你可以看看是否(ChromeWebBrowser.net || GeckoWebBrowser)这个是否能帮上你,虽然它是大了一点,不对,是大了很多

    ChromeWebBrowser.net - Chrome

    http://sourceforge.net/projects/chromewebbrowse/files/    - 下载

    http://blog.csdn.net/lllllllllluoyi/article/details/28716653

    GeckoWebBrowser - Firefox

    http://code.google.com/p/geckofx/                                   - 下载

    http://www.cnblogs.com/zhuo/archive/2010/03/19/1690237.html

  • 相关阅读:
    AOSP 设置编译输出目录
    android stadio 编译报错:download fastutil-7.2.0.jar
    Ubuntu adb 报错:no permissions (user in plugdev group; are your udev rules wrong?);
    Ubuntu 18启动失败 Started Hold until boot procss finishes up
    算法---------两数之和
    Windows 显示环境变量
    Android ObjectOutputStream Serializable引发的血案
    (AOSP)repo checkout指定版本
    如果看懂git -help
    Android stado 运行项目,apk does not exist on disk.
  • 原文地址:https://www.cnblogs.com/lxmyn/p/3947616.html
Copyright © 2020-2023  润新知