【问题标题】:WebBrowser OnPropertyChange event is not firingWebBrowser OnPropertyChange 事件未触发
【发布时间】:2012-12-10 12:30:42
【问题描述】:

我有一个网页,上面有一个输入按钮。单击此按钮,在特定的 div 中加载一些数据。我的问题是我无法捕捉到这些数据。

以下代码是我尝试解决这个问题,但没有成功。

private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
    HtmlElement div_result = webBrowser1.Document.GetElementById("div_result");
    div_result.AttachEventHandler("onpropertychange", new EventHandler(resultEventHandler));
}
private void resultEventHandler(object sender, EventArgs e)
{
    MessageBox.Show("Loaded");
}

如果我点击输入按钮,div 的内容会被修改,但resultEventHandler 不会触发。

所以,我有两个问题:

  1. 这段代码我的错在哪里?
  2. 在 C# 中使用 WebBrowser 控件来处理 ajax 是否有“正常方式”(我的意思是不使用计时器或 Aplication.DoEvents())?

【问题讨论】:

标签: c# html winforms webbrowser-control propertychanged


【解决方案1】:

这可能为时已晚,但无论如何,如果您仍然想知道:

1 - HtmlElement div_result = webBrowser1.Document.GetElementById("div_result"); 第 1 行在网页加载完毕并且浏览器调用 DocumentCompleted 事件时执行。在事件处理程序中,您首先检索指向 DOM 元素“div_result”的指针,然后分配一个名为 div_result 的 HtmlElement 类型变量。

2 - div_result.AttachEventHandler("onpropertychange", new EventHandler(resultEventHandler)); 第 2 行 - 注册“onpropertychange”事件并将方法 resultEventHandler 分配为侦听器方法。

每次您点击网页上的按钮时,按钮(我假设)都会以提交的表单形式出现,从而导致网页加载;顺便说一句,您没有指定单击按钮时使用的发布方法(获取或发布)。当网页下载完成并构建 DOM 元素树时,将调用 DocumentCompleted 事件。您为 DocumentCompleted 事件处理程序方法执行了上述说明。

每次单击按钮时,都会重新加载网页,并为 onpropertychange 事件重新分配事件侦听器。您只是分配事件侦听器。该事件将永远不会被调用。每次单击按钮时都会定义它。你有一个经典的先有鸡或先有蛋的问题。但是在您的情况下,您的鸡是导致 DocumentCompleted 方法运行的按钮单击事件,该方法会重置该方法中所有变量的状态,并且您的蛋需要在网络上单击按钮之前指向 DIV 元素的 onpropertychange 事件的指针页 。在从尚未构造的 DOM 中获取指针之前,如何将事件侦听器分配给 htmlelement?在包含 DocumentCompleted 方法的类中放置一个布尔标志变量并设置其初始状态。将 div_result 变量移到 DocumentCompleted 方法之外,以增加其范围并在按钮单击事件中保存其状态。这样,您将获得指向 div 元素的指针,并在第一次下载网页时设置其 onpropertychange 事件侦听器。如果您只想设置一个指向 DIV 元素的 onpropertychange 事件侦听器的指针,请添加一个测试(我在下面的示例代码中放置了一个),并且下次单击按钮时,您的事件将触发。笔记!确保在存储指向任何网页元素或其事件的指针后,不要向网页添加或删除任何元素。否则,您将不得不重新解析 DOM 以获取指向元素在 DOM 树中的新位置的指针。

//见下图:

class SomeClass
{
    bool DocumentHasLoaded = false;
    HtmlElement div_result = null;

    //Constructor and other methods go here....

    //Then change your DocumentCompleted method to look like this:
    private void webBrowser1_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
    {

        if (DocumentHasLoaded == false)  // I prefer using a ! before the variable instead
        {
            DocumentHasLoaded = true;    // You will have to create your own appropriately timed mechanism to reset this variable's state should you want to execute the whole process again.
            div_result = webBrowser1.Document.GetElementById("div_result");
            div_result.AttachEventHandler("onpropertychange", new EventHandler(resultEventHandler));
        }
    }
}

为了回答您的第二个问题,我需要有关 DIV 中加载的数据的更多信息;例如它来自哪里,它是什么类型,以及您能想到的任何其他相关信息。

【讨论】:

  • “我更喜欢在变量之前使用 !” 那为什么还要做其他事情呢? - 这是你的答案
  • 如果按钮单击导致页面刷新,则此分析是有意义的。但是,如果按钮单击触发页面中的某些(客户端)javascript,其中 JS 更改了“div_result”元素,那么 onpropertychange 应该 的 C# 事件处理程序会被触发,不是吗? FWIW 我有一个类似的案例,其中 C# 事件处理程序曾经被调用,但现在它没有。我目前怀疑由于 Windows 更新导致 MSIE 中的行为发生变化。见also
【解决方案2】:

我不知道为什么 HtmlElement 事件对你不起作用。但是我遇到了同样的问题并通过使用 COM 包装器解决了它:

mshtml.HTMLDocumentClass doc = (mshtml.HTMLDocumentClass)webBrowser1.Document.DomDocument;
mshtml.IHTMLElement2 div_result = (mshtml.IHTMLElement2)doc.getElementById("div_result");
mshtml.HTMLElementEvents2_Event events = (mshtml.HTMLElementEvents2_Event)div_result;
events.onpropertychange += resultEventHandler;

【讨论】:

    【解决方案3】:

    更改子元素的 innerText 或 innerHTML 不会导致父元素的 onpropertychange 事件触发。

    【讨论】:

    • 我从 msdn 阅读了这篇笔记,但我没有子元素。我有一个非常 simple webpage ,我为这个实验做了特别的。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-07-05
    • 2014-05-13
    • 2014-04-27
    • 2010-10-15
    • 2012-02-29
    • 1970-01-01
    相关资源
    最近更新 更多