我正在使用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()
“问题”,但我找不到任何其他方法来做到这一点。解决这个问题的另一种方法也非常受欢迎。
答案 0 :(得分:1)
如果您使用的是.NET 4.5或更高版本(如果您愿意使用Microsoft.Bcl.Async库,则可以使用4.0),这可以通过TaskCompletionSource
和await
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,但你可能不得不这样做。