WebBrowser有Application.DoEvents()吗?

时间:2014-11-16 17:07:29

标签: c# .net events timer browser

我正在使用Timer来确定使用AJAX加载的页面是否准备就绪,并且只有在准备就绪时才从函数返回(加载包含ajax内容的页面加载)。我正在尝试下面的代码,但我发现Application.DoEvents()只处理挂起的Windows消息循环项,因此它会遇到无限循环,因为Applicadion.DoEvents()不会引发任何WebBrowser的事件(但我只提到了一个Windows),因此ReadyState无法更新,也永远无法更改。

我的问题是:有没有办法强制WebBrowser's事件Application.DoEvents()呢?

static bool done = false;
int[] foo()
{
  int[] data;
 timer1.Interval = 1000;
            timer1.Tick += new EventHandler(delegate(object o, EventArgs ea)
                {
                    if (browser.ReadyState == WebBrowserReadyState.Complete)
                    {
                        timer1.Stop();
                        data = extract_data();
                        done = true;
                    }
                });
            timer1.Start();

            while(!done) /* return from function only if timer1 isn't running anymore */
            {
                Application.DoEvents();
                Thread.Sleep(1000);
            }

            return data;
}

我知道Application.DoEvents()“问题”,但我找不到任何其他方法来做到这一点。解决这个问题的另一种方法也非常受欢迎。

2 个答案:

答案 0 :(得分:1)

如果您使用的是.NET 4.5或更高版本(如果您愿意使用Microsoft.Bcl.Async库,则可以使用4.0),这可以通过TaskCompletionSourceawait

async Task<int[]> foo()
{
    //Create the completion source and the callback delegate.
    var tcs = new TaskCompletionSource<object>();
    WebBrowserDocumentCompletedEventHandler callback = (sender, args) => tcs.SetResult(null);

    //Subscribe to the Document completed event and run the callback.
    browser.DocumentCompleted += callback;

    try
    {
        //We may already be in the complete state so the event will never fire.
        //Therefor if we are in the completed state we can skip the await.
        if (browser.ReadyState != WebBrowserReadyState.Complete)
        {
            //Wait here for the completed event to fire.
            await tcs.Task;
        }
    }
    finally
    {
        //Unsubscribe the callback which is nolonger needed.
        browser.DocumentCompleted -= callback;
    }

    //Process the data from the completed document.
    var data = extract_data();
    return data;
}

此代码将执行的操作是订阅DocumentCompleted事件,然后可选择等待文档完成但尚未完成加载,同时等待它将控制权返回给调用者(效果与你的DoEvents循环,但更好)一旦事件触发它处理数据并返回结果。

但是,如果可能的话,更好的解决方案就是重新编写代码,永远不要调用foo,只需订阅DocumentCompleted事件,然后将数据推送到需要的地方而不是拉它。

答案 1 :(得分:1)

在Visual Studio中,双击WebBrowser控件。这将为DocumentCompleted事件创建一个事件处理程序。您可以使用任何其他机制来创建DocumentCompleted事件处理程序,但该事件是重要的部分。有关示例,请参阅我的文章Introduction to Web Site Scraping

请不要使用Application.DoEvents(),ReadyState或Thread.Sleep。

如果网页使用脚本生成页面的某些部分,则问题可能很复杂。如果发生这种情况,那么我会尽我所能避免使用Thread.Sleep,但你可能不得不这样做。