65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 C# 从 .NET 处理 HTML 事件

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.88/5 (22投票s)

2008 年 5 月 3 日

CPOL

3分钟阅读

viewsIcon

94992

downloadIcon

1816

本文演示了一种简单的方法,可以从 .NET WinForms 应用程序、BandObject 或浏览器辅助对象绑定到任何 HTML 文档事件。

HtmlEventsSmple

前言

我不是以英语为母语的人,也不打算获得普利策新闻奖。 因此,如果有人觉得这篇“文章”有点短,请耐心等待。 我的目的是提供最有用的信息,而不是说太多。 此外,我的 C# 英语对于 VS2005 编译器来说已经足够好了 :-)。 我希望本文的读者能够找到他们通过 Google 搜索“在 .NET 中处理 HTML 事件”所得到的答案。

背景

我一直在寻找一种使用 .NET EventHandler 处理 HTML 事件的方法。 在编写我的 密码管理工具栏时,我需要一种方法来钩住 HTML 文档表单的“onsubmit”事件,以便检查登录信息。

无论如何,我寻找论坛和线程,希望能给我一个直接的答案,但没有找到。 因此,我别无选择,只能求助于最后的方法:Reflector(Luts Roeder 的 .NET Reflector)。

我在寻找什么? 在使用 WebBrowser 控件时,您会得到 HtmlElement 包装类,该类允许您非常轻松地绑定到鼠标事件(例如 HtmlElement.Click 事件)。 但是,我不使用 WebBrowser 控件、BandObject(这是工具栏对象)或浏览器辅助对象 (BHO),它们只能访问 MSHTML DOM 元素。 此外,托管包装器没有提供“onsubmit”的事件,因此即使是 WebBrowser 控件也不适合我。 因此,我开始使用 Reflector 进行挖掘,看看 Microsoft 的人在允许绑定到鼠标事件方面做了什么。 我发现的主要内容是 HtmlToClrEventProxy 类,它为 IHTMLElement2.attachEvent 方法所需的对象提供了正确的接口。 无论如何,这个类是内部的,所以我采用了其中的大部分内容,对其进行了改进,并制作了一个类似的公共版本,允许 .NET 用户轻松地附加到任何 HTMLElement 事件。

使用代码

最好的方法是先下载并尝试示例。 您只需要将一个类添加到您的项目中,这就是 HtmlEventProxy 类。 这个类有一个工厂方法 Create(),它将完成所有的绑定。 然后,当您想要从事件中分离时,只需调用对象的 Detach() 方法即可。 EventHandler 中的“sender”对象是代理本身。 为了获得底层的 HTMLElement,请使用 HtmlElement 属性。 以下是一些来自示例的代码片段

让我们从 onsubmit 表单事件的 .NET 事件处理程序开始。 它具有 EventHandler 的常规签名。 这里的代码还从发送者中提取表单元素并显示其 outerHTML 字符串。

我选择在使用 Detach() 方法后从事件中分离。

private void FormSubmitHabdler(object sender, EventArgs e)
{
    MessageBox.Show("form submitted");

    // show the outer html of the form
    IHTMLElement form = 
         ((HtmlEventProxy)sender).HTMLElement as IHTMLElement;
    MessageBox.Show("outer html:" + form.outerHTML);

    //detach the event from the element
    ((HtmlEventProxy)sender).Detach();
}

现在,对于将表单 onsubmit 事件绑定到处理程序的代码

object form = webBrowser1.Document.Forms[0].DomElement ; 
HtmlEventProxy.Create("onsubmit", form, FormSubmitHabdler);
 
object button = webBrowser1.Document.GetElementById("button1").DomElement; 
HtmlEventProxy.Create("onclick", button, ButtonClickHabdler);

首先,从文档中获取元素对象。 然后,使用事件名称、DOM 元素和 .NET 处理程序创建一个代理。

“HtmlEventProxy”类

该类实现了 IReflect 接口; 这是 IHTMLElement2.attachEvent(string ev,object pDisp) 所需的接口。 最重要的是 IReflect.InvokeMember 方法的实现。 此方法检测对第一个方法条目的调用并执行 .NET 处理程序。

我还实现了 IDisposable 接口,因此当代理被释放时,事件会被分离。

public class HtmlEventProxy : IDisposable,IReflect 
{ 
 // Fields private EventHandler eventHandler; 
 private object sender; 
 private IReflect typeIReflectImplementation; 
 private IHTMLElement2 htmlElement = null; 
 private string eventName = null; 

 // private CTOR 
 private HtmlEventProxy(string eventName, IHTMLElement2 htmlElement, 
                        EventHandler eventHandler) 
 { 
   this.eventName = eventName; 
   this.htmlElement = htmlElement; 
   this.sender = this; 
   this.eventHandler = eventHandler;
   Type type = typeof(HtmlEventProxy); 
   this.typeIReflectImplementation = type; 
 }

 public static HtmlEventProxy Create(string eventName, 
               object htmlElement, EventHandler eventHandler) 
 {
   IHTMLElement2 elem = (IHTMLElement2)htmlElement; 
   HtmlEventProxy newProxy = new HtmlEventProxy(eventName,elem, eventHandler); 
   elem.attachEvent(eventName, newProxy); return newProxy; 
 }

 /// detach only once (thread safe) 
 /// 
 public void Detach() 
 { 
   lock (this)
   { 
     if (this.htmlElement != null) 
     {
       IHTMLElement2 elem = (IHTMLElement2)htmlElement; 
       elem.detachEvent(this.eventName, this);
       this.htmlElement = null; 
     } 
   } 
 } 

 /// HtmlElemet property 
 /// 
 public IHTMLElement2 HTMLElement 
 {
   get 
   { 
     return this.htmlElement; 
   } 
 } 

 #region IReflect

 ......

 object IReflect.InvokeMember(string name,BindingFlags invokeAttr, Binder binder, 
                 object target, object[] args, ParameterModifier[] modifiers, 
                 CultureInfo culture, string[] namedParameters) 
 {
   if (name == "[DISPID=0]") 
   { 
     if (this.eventHandler != null) 
     {
       this.eventHandler(this.sender, EventArgs.Empty); 
     } 
   }
   return null; 
 }

#endregion 
}

您可以从这里下载最新版本的HtmlEventProxy.cs

尽情享用!

© . All rights reserved.