C# 从WebBrowser控件获取ReadyState而不使用DoEvents
这已经在这里和其他站点及其工作中多次使用,但我希望通过其他方式: 在使用导航或post后获取ReadyState=Complete,由于其所有缺点,不使用DoEvents 我还要指出,在这里使用DocumentComplete事件没有帮助,因为我不会只浏览一个页面,而是像这样一个接一个地浏览C# 从WebBrowser控件获取ReadyState而不使用DoEvents,c#,.net,webbrowser-control,readystate,doevents,C#,.net,Webbrowser Control,Readystate,Doevents,这已经在这里和其他站点及其工作中多次使用,但我希望通过其他方式: 在使用导航或post后获取ReadyState=Complete,由于其所有缺点,不使用DoEvents 我还要指出,在这里使用DocumentComplete事件没有帮助,因为我不会只浏览一个页面,而是像这样一个接一个地浏览 wb.navigate("www.microsoft.com") //dont use DoEvents loop here wb.Document.Body.SetAttribute(textbox1,
wb.navigate("www.microsoft.com")
//dont use DoEvents loop here
wb.Document.Body.SetAttribute(textbox1, "login")
//dont use DoEvents loop here
if (wb.documenttext.contais("text"))
//do something
它现在的工作方式是使用DoEvents。我想知道是否有人有一个合适的方法来等待浏览器方法的异步调用,然后继续进行其余的逻辑。只是为了它
提前感谢。这里有一个“快速脏”的解决方案。它不是100%万无一失的,但它不会阻止UI线程,而且应该能够满足WebBrowser控制自动化程序原型的要求:
private async void testButton_Click(object sender, EventArgs e)
{
await Task.Factory.StartNew(
() =>
{
stepTheWeb(() => wb.Navigate("www.yahoo.com"));
stepTheWeb(() => wb.Navigate("www.microsoft.com"));
stepTheWeb(() => wb.Navigate("asp.net"));
stepTheWeb(() => wb.Document.InvokeScript("eval", new[] { "$('p').css('background-color','yellow')" }));
bool testFlag = false;
stepTheWeb(() => testFlag = wb.DocumentText.Contains("Get Started"));
if (testFlag) { /* TODO */ }
// ...
}
);
}
private void stepTheWeb(Action task)
{
this.Invoke(new Action(task));
WebBrowserReadyState rs = WebBrowserReadyState.Interactive;
while (rs != WebBrowserReadyState.Complete)
{
this.Invoke(new Action(() => rs = wb.ReadyState));
System.Threading.Thread.Sleep(300);
}
}
下面是一个更通用的testButton\u点击方法:
private async void testButton_Click(object sender, EventArgs e)
{
var actions = new List<Action>()
{
() => wb.Navigate("www.yahoo.com"),
() => wb.Navigate("www.microsoft.com"),
() => wb.Navigate("asp.net"),
() => wb.Document.InvokeScript("eval", new[] { "$('p').css('background-color','yellow')" }),
() => {
bool testFlag = false;
testFlag = wb.DocumentText.Contains("Get Started");
if (testFlag) { /* TODO */ }
}
//...
};
await Task.Factory.StartNew(() => actions.ForEach((x)=> stepTheWeb (x)));
}
下面是一个基本的WinForms应用程序代码,说明了如何使用async/await
异步等待DocumentCompleted
事件。它一个接一个地导航到多个页面。一切都发生在主UI线程上
与其调用this.webBrowser.Navigate(url)
,不如模拟表单按钮单击,以触发帖子样式的导航
webBrowser.IsBusy
异步循环逻辑是可选的,其目的是(非确定性地)说明页面的动态AJAX代码,该代码可能发生在window.onload
事件之后
using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Forms;
namespace WebBrowserApp
{
public partial class MainForm : Form
{
WebBrowser webBrowser;
public MainForm()
{
InitializeComponent();
// create a WebBrowser
this.webBrowser = new WebBrowser();
this.webBrowser.Dock = DockStyle.Fill;
this.Controls.Add(this.webBrowser);
this.Load += MainForm_Load;
}
// Form Load event handler
async void MainForm_Load(object sender, EventArgs e)
{
// cancel the whole operation in 30 sec
var cts = new CancellationTokenSource(30000);
var urls = new String[] {
"http://www.example.com",
"http://www.gnu.org",
"http://www.debian.org" };
await NavigateInLoopAsync(urls, cts.Token);
}
// navigate to each URL in a loop
async Task NavigateInLoopAsync(string[] urls, CancellationToken ct)
{
foreach (var url in urls)
{
ct.ThrowIfCancellationRequested();
var html = await NavigateAsync(ct, () =>
this.webBrowser.Navigate(url));
Debug.Print("url: {0}, html: \n{1}", url, html);
}
}
// asynchronous navigation
async Task<string> NavigateAsync(CancellationToken ct, Action startNavigation)
{
var onloadTcs = new TaskCompletionSource<bool>();
EventHandler onloadEventHandler = null;
WebBrowserDocumentCompletedEventHandler documentCompletedHandler = delegate
{
// DocumentCompleted may be called several time for the same page,
// if the page has frames
if (onloadEventHandler != null)
return;
// so, observe DOM onload event to make sure the document is fully loaded
onloadEventHandler = (s, e) =>
onloadTcs.TrySetResult(true);
this.webBrowser.Document.Window.AttachEventHandler("onload", onloadEventHandler);
};
this.webBrowser.DocumentCompleted += documentCompletedHandler;
try
{
using (ct.Register(() => onloadTcs.TrySetCanceled(), useSynchronizationContext: true))
{
startNavigation();
// wait for DOM onload event, throw if cancelled
await onloadTcs.Task;
}
}
finally
{
this.webBrowser.DocumentCompleted -= documentCompletedHandler;
if (onloadEventHandler != null)
this.webBrowser.Document.Window.DetachEventHandler("onload", onloadEventHandler);
}
// the page has fully loaded by now
// optional: let the page run its dynamic AJAX code,
// we might add another timeout for this loop
do { await Task.Delay(500, ct); }
while (this.webBrowser.IsBusy);
// return the page's HTML content
return this.webBrowser.Document.GetElementsByTagName("html")[0].OuterHtml;
}
}
}
使用系统;
使用系统诊断;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows.Forms;
命名空间WebBrowserApp
{
公共部分类主窗体:窗体
{
网络浏览器;
公共表格(
{
初始化组件();
//创建网络浏览器
this.webBrowser=新的webBrowser();
this.webBrowser.Dock=DockStyle.Fill;
this.Controls.Add(this.webBrowser);
此.Load+=MainForm_Load;
}
//表单加载事件处理程序
异步void MainForm_加载(对象发送方,事件参数e)
{
//在30秒内取消整个操作
var cts=新的CancellationTokenSource(30000);
var url=新字符串[]{
"http://www.example.com",
"http://www.gnu.org",
"http://www.debian.org" };
等待NavigateInLopAsync(URL、cts.Token);
}
//导航到循环中的每个URL
异步任务NavigateInLopAsync(字符串[]URL,CancellationToken ct)
{
foreach(url中的变量url)
{
ct.ThrowIfCancellationRequested();
var html=await NavigateAsync(ct,()=>
this.webBrowser.Navigate(url));
Print(“url:{0},html:\n{1}”,url,html);
}
}
//异步导航
异步任务NavigateAsync(取消令牌ct,操作开始导航)
{
var onload tcs=new TaskCompletionSource();
EventHandler onloadEventHandler=null;
WebBrowserDocumentCompletedEventHandler documentCompletedHandler=委托
{
//对于同一页,DocumentCompleted可以多次调用,
//如果页面有框架
if(onloadEventHandler!=null)
返回;
//因此,观察DOM onload事件以确保文档已完全加载
onloadEventHandler=(s,e)=>
onload tcs.TrySetResult(真);
this.webBrowser.Document.Window.AttachEventHandler(“onload”,onloadEventHandler);
};
this.webBrowser.DocumentCompleted+=documentCompletedHandler;
尝试
{
使用(ct.Register(()=>onload tcs.trysetconceled(),useSynchronizationContext:true))
{
startNavigation();
//等待DOM onload事件,如果取消则抛出
等待onload任务;
}
}
最后
{
this.webBrowser.DocumentCompleted-=documentCompletedHandler;
if(onloadEventHandler!=null)
this.webBrowser.Document.Window.DetachEventHandler(“onload”,onloadEventHandler);
}
//现在页面已完全加载
//可选:让页面运行其动态AJAX代码,
//我们可能会为此循环添加另一个超时
不要{等待任务。延迟(500,ct);}
而(这个.webBrowser.IsBusy);
//返回页面的HTML内容
返回此.webBrowser.Document.GetElementsByTagName(“html”)[0].OuterHtml;
}
}
}
如果您希望从控制台应用程序中执行类似的操作,请参见。解决方案很简单:
// MAKE SURE ReadyState = Complete
while (WebBrowser1.ReadyState.ToString() != "Complete") {
Application.DoEvents();
}
//转到您的子序列代码
又脏又快。。我是一个VBA的家伙,这种逻辑一直在发挥作用,只是花了我几天的时间,却找不到适合C#的,但我自己刚刚发现了这一点
以下是我的完整功能,目标是从网页中获取一段信息:
private int maxReloadAttempt = 3;
private int currentAttempt = 1;
private string GetCarrier(string webAddress)
{
WebBrowser WebBrowser_4MobileCarrier = new WebBrowser();
string innerHtml;
string strStartSearchFor = "subtitle block pull-left\">";
string strEndSearchFor = "<";
try
{
WebBrowser_4MobileCarrier.ScriptErrorsSuppressed = true;
WebBrowser_4MobileCarrier.Navigate(webAddress);
// MAKE SURE ReadyState = Complete
while (WebBrowser_4MobileCarrier.ReadyState.ToString() != "Complete") {
Application.DoEvents();
}
// LOAD HTML
innerHtml = WebBrowser_4MobileCarrier.Document.Body.InnerHtml;
// ATTEMPT (x3) TO EXTRACT CARRIER STRING
while (currentAttempt <= maxReloadAttempt) {
if (innerHtml.IndexOf(strStartSearchFor) >= 0)
{
currentAttempt = 1; // Reset attempt counter
return Sub_String(innerHtml, strStartSearchFor, strEndSearchFor, "0"); // Method: "Sub_String" is my custom function
}
else
{
currentAttempt += 1; // Increment attempt counter
GetCarrier(webAddress); // Recursive method call
} // End if
} // End while
} // End Try
catch //(Exception ex)
{
}
return "Unavailable";
}
private int maxreloadtright=3;
private int currenttrunt=1;
私有字符串GetCarrier(字符串Web地址)
{
WebBrowser WebBrowser_4MobileCarrier=新WebBrowser();
字符串innerHtml;
字符串strStartSearchFor=“subtitle block pull left\”>”;
string Strength SearchFor=“您必须使用DocumentCompleted事件。您需要做的只是跟踪已完成的内容。事件已经告诉您,您将返回e.Url属性。如果您需要了解更多信息,则只需使用跟踪状态的变量。简单的整数或枚举即可
private int maxReloadAttempt = 3;
private int currentAttempt = 1;
private string GetCarrier(string webAddress)
{
WebBrowser WebBrowser_4MobileCarrier = new WebBrowser();
string innerHtml;
string strStartSearchFor = "subtitle block pull-left\">";
string strEndSearchFor = "<";
try
{
WebBrowser_4MobileCarrier.ScriptErrorsSuppressed = true;
WebBrowser_4MobileCarrier.Navigate(webAddress);
// MAKE SURE ReadyState = Complete
while (WebBrowser_4MobileCarrier.ReadyState.ToString() != "Complete") {
Application.DoEvents();
}
// LOAD HTML
innerHtml = WebBrowser_4MobileCarrier.Document.Body.InnerHtml;
// ATTEMPT (x3) TO EXTRACT CARRIER STRING
while (currentAttempt <= maxReloadAttempt) {
if (innerHtml.IndexOf(strStartSearchFor) >= 0)
{
currentAttempt = 1; // Reset attempt counter
return Sub_String(innerHtml, strStartSearchFor, strEndSearchFor, "0"); // Method: "Sub_String" is my custom function
}
else
{
currentAttempt += 1; // Increment attempt counter
GetCarrier(webAddress); // Recursive method call
} // End if
} // End while
} // End Try
catch //(Exception ex)
{
}
return "Unavailable";
}