UMPLatForm.NET 中MiNiWeb浏览器核心技术详解三
接上两篇:
UMPLatForm.NET 中MiNiWeb浏览器核心技术详解一
UMPLatForm.NET 中MiNiWeb浏览器核心技术详解二
实现dwebbrowserevents2接口
在这个例子中实现了下列事件:
l newwindow2和newwindow3(用于屏蔽弹出窗口和创建新窗口)
l downloadbegin和downloadcomplete(用于捕捉脚本错误)
l beforenavigate2(用于在导航到一个页面前查看即将导航到的地址)
为了简洁的实现dwebbrowserevents接口,最好的方法是在组件中建立一个私有的嵌入类。这样,所有需要的事件都在一个地方并且轻易查找。当我们实例化这个类的时候,我们可以给调用者提供一个引用,利用该引用可以调用方法来触发我们需要的事件。
在组件的构造过程中并没有附带这些事件,而是稍微晚一点。这里有两个方法来实现它并且它们是可以重载的。它们是createsink()和detachsink()。当我们将这些都添加完以后,我们的代码会像下面这样(注重有些代码为了阅读方便而删掉了)
- /// <summary>
- /// An extended version of the <see cref="WebBrowser"/> control.
- /// </summary>
- public class extendedwebbrowser : system.windows.forms.webbrowser
- {
- // (MORE CODE HERE)
- SYSTEM.WINDOWS.FORMS.AXHOST.CONNECTIONPOINTCOOKIE COOKIE;
- WEBBROWSEREXTENDEDEVENTS EVENTS;
- /// <SUMMARY>
- /// THIS METHOD WILL BE CALLED TO GIVE
- /// YOU A CHANCE TO CREATE YOUR OWN EVENT SINK
- /// </SUMMARY>
- [PERMISSIONSET(SECURITYACTION.LINKDEMAND, NAME = "FULLTRUST")]
- PROTECTED OVERRIDE VOID CREATESINK()
- {
- // MAKE SURE TO CALL THE BASE CLASS OR THE NORMAL EVENTS WON'T FIRE
- BASE.CREATESINK();
- EVENTS = NEW WEBBROWSEREXTENDEDEVENTS(THIS);
- COOKIE = NEW AXHOST.CONNECTIONPOINTCOOKIE(THIS.ACTIVEXINSTANCE,
- EVENTS, TYPEOF(UNSAFENATIVEMETHODS.DWEBBROWSEREVENTS2));
- }
- /// <SUMMARY>
- /// DETACHES THE EVENT SINK
- /// </SUMMARY>
- [PERMISSIONSET(SECURITYACTION.LINKDEMAND, NAME = "FULLTRUST")]
- PROTECTED OVERRIDE VOID DETACHSINK()
- {
- IF (NULL != COOKIE)
- {
- COOKIE.DISCONNECT();
- COOKIE = NULL;
- }
- }
- /// <SUMMARY>
- /// FIRES WHEN DOWNLOADING OF A DOCUMENT BEGINS
- /// </SUMMARY>
- PUBLIC EVENT EVENTHANDLER DOWNLOADING;
- /// <SUMMARY>
- /// RAISES THE <SEE CREF="DOWNLOADING"/> EVENT
- /// </SUMMARY>
- /// <PARAM NAME="E">EMPTY <SEE CREF="EVENTARGS"/></PARAM>
- /// <REMARKS>
- /// YOU COULD START AN ANIMATION
- /// OR A NOTIFICATION THAT DOWNLOADING IS STARTING
- /// </REMARKS>
- PROTECTED VOID ONDOWNLOADING(EVENTARGS E)
- {
- IF (DOWNLOADING != NULL)
- DOWNLOADING(THIS, E);
- }
- // (MORE CODE HERE)
- THE IMPLEMENTATION OF DWEBBROWSEREVENTS2 FOR FIRING EXTRA EVENTS
- }
4、使用这个组件
上一节,我们创建了一个新的组件。现在,我们来使用这些新的事件并尽可能多的挖掘浏览器的功能。针对每一个目标,具体的解释如下:
捕捉脚本错误
在示例程序中,有一个工具窗口简单的显示了发生错误的列表并附带了错误的具体内容。一个单一实例类把握了脚本错误的信息并且当这个信息发生改变时通知所有订阅者,为了捕捉这些脚本错误,browsercontrol首先附加到downloadcomplete事件,其次它订阅了htmlwindow.error事件。当这个事件触发时,我们注册这个脚本错误并设置handled属性为true。
- public partial class browsercontrol : usercontrol
- {
- public browsercontrol()
- {
- initializecomponent();
- _browser = new extendedwebbrowser();
- _browser.dock = dockstyle.fill;
- // here's the new downloadcomplete event
- _browser.downloadcomplete +=
- new eventhandler(_browser_downloadcomplete);
- // some more code here
- this.containerpanel.controls.add(_browser);
- // some more code here
- }
- 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;
- }
- // some more code here
- }
过滤弹出窗口,并且增加多标签页或多窗口浏览功能
捕捉弹出窗口必须可以由用户来进行配置。为了示范的目的,我实现了四个级别,从不屏蔽任何窗口到屏蔽所有新窗口。下面的代码是browsercontorl的一部分,用来展现如何实现这一点。当一个新建窗口被答应后,示例程序展现了如何让新建窗口实现窗口名称的解决方案。
- void _browser_startnewwindow(object sender,
- browserextendednavigatingeventargs e)
- {
- // here we do the pop-up blocker work
- // note that in windows 2000 or lower this event will fire, but the
- // event arguments will not contain any useful information
- // for blocking pop-ups.
- // there are 4 filter levels.
- // none: allow all pop-ups
- // low: allow pop-ups from secure sites
- // medium: block most pop-ups
- // high: block all pop-ups (use ctrl to override)
- // we need the instance of the main form,
- // because this holds the instance
- // to the windowmanager.
- mainform mf = getmainformfromcontrol(sender as control);
- if (mf == null)
- return;
- // allow a popup when there is no information
- // available or when the ctrl key is pressed
- bool allowpopup = (e.navigationcontext == urlcontext.none)
- || ((e.navigationcontext &
- urlcontext.overridekey) == urlcontext.overridekey);
- if (!allowpopup)
- {
- // give none, low & medium still a chance.
- switch (settingshelper.current.filterlevel)
- {
- case popupblockerfilterlevel.none:
- allowpopup = true;
- break;
- case popupblockerfilterlevel.low:
- // see if this is a secure site
- if (this.webbrowser.encryptionlevel !=
- webbrowserencryptionlevel.insecure)
- allowpopup = true;
- else
- // not a secure site, handle this like the medium filter
- goto case popupblockerfilterlevel.medium;
- break;
- case popupblockerfilterlevel.medium:
- // this is the most dificult one.
- // only when the user first inited
- // and the new window is user inited
- if ((e.navigationcontext & urlcontext.userfirstinited)
- == urlcontext.userfirstinited &&
- (e.navigationcontext & urlcontext.userinited)
- == urlcontext.userinited)
- allowpopup = true;
- break;
- }
- }
- 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;
- }
- }
- else
- // here you could notify the user that the pop-up was blocked
- e.cancel = true;
- }
这个事件称为startnewwindow的原因是编码设计规则不答应一个事件的名称以“before”或者“after”开头。“newwindowing”事件并没有在这一范围内。
使用quit事件
当quit事件触发时,我们只需要找到正确的窗口或者标签页将其关闭,并且”dispose”这个示例即可。
作者: Edward
出处: http://umplatform.blog.51cto.com/
微博: 腾讯
Email: [email protected]或 [email protected]
QQ 交流:406590790 (请注明:平台交流)
QQ群交流:16653241 或 237326100
关于作者:高级工程师、信息系统项目管理师、数据库系统工程师。专注于微软平台项目架构、管理和企业解决方案,多年项目开发与管理经验,曾多次组织并开发多个大型项目,精通DotNet(C#、Asp.NET、ADO.NET、Web Service、WCF),DB原理与技术、SqlServer、Oracle等。熟悉Java、Delhpi及Linux操作系统,有扎实的网络知识。自认在面向对象、面向服务以及数据库领域有一定的造诣。现主要从事DB管理、DB开发、WinForm、WCF、WebService、网页数据抓取以及ASP.NET等项目管理、开发、架构等工作。如有问题或建议,请多多赐教!
本文版权归作者和51CTO博客共有,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原文连接,如有问题,可以通过邮箱或QQ 联系我,非常感谢。