C# 新线程中的WebBrowser控件
我有一个列表Uri,我希望单击它来实现这一点。我正在尝试为每个Uri创建一个新的web浏览器控件。我为每个Uri创建一个新线程。我遇到的问题是,线程在文档完全加载之前就结束了,所以我永远无法使用DocumentComplete事件。我如何克服这个问题C# 新线程中的WebBrowser控件,c#,multithreading,browser,C#,Multithreading,Browser,我有一个列表Uri,我希望单击它来实现这一点。我正在尝试为每个Uri创建一个新的web浏览器控件。我为每个Uri创建一个新线程。我遇到的问题是,线程在文档完全加载之前就结束了,所以我永远无法使用DocumentComplete事件。我如何克服这个问题 var item = new ParameterizedThreadStart(ClicIt.Click); var thread = new Thread(item) {Name = "ClickThread"}; thread.Start(
var item = new ParameterizedThreadStart(ClicIt.Click);
var thread = new Thread(item) {Name = "ClickThread"};
thread.Start(uriItem);
public static void Click(object o)
{
var url = ((UriItem)o);
Console.WriteLine(@"Clicking: " + url.Link);
var clicker = new WebBrowser { ScriptErrorsSuppressed = true };
clicker.DocumentCompleted += BrowseComplete;
if (String.IsNullOrEmpty(url.Link)) return;
if (url.Link.Equals("about:blank")) return;
if (!url.Link.StartsWith("http://") && !url.Link.StartsWith("https://"))
url.Link = "http://" + url.Link;
clicker.Navigate(url.Link);
}
根据我过去的经验,webbrowser不喜欢在主应用程序线程之外操作 尝试改用httpwebrequests,您可以将它们设置为异步,并为响应创建一个处理程序,以便知道响应何时成功:
您必须创建一个STA线程来泵送消息循环。这是像WebBrowser这样的ActiveX组件唯一适合的环境。否则您将无法获得DocumentCompleted事件。一些示例代码:
private void runBrowserThread(Uri url) {
var th = new Thread(() => {
var br = new WebBrowser();
br.DocumentCompleted += browser_DocumentCompleted;
br.Navigate(url);
Application.Run();
});
th.SetApartmentState(ApartmentState.STA);
th.Start();
}
void browser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e) {
var br = sender as WebBrowser;
if (br.Url == e.Url) {
Console.WriteLine("Natigated to {0}", e.Url);
Application.ExitThread(); // Stops the thread
}
}
下面是如何在非UI线程上组织消息循环,以运行异步任务,如
WebBrowser
自动化。它用于提供方便的线性代码流,并在循环中加载一组网页。该代码是一个准备运行的控制台应用程序,部分基于
有关答案:
使用系统;
使用系统线程;
使用System.Threading.Tasks;
使用System.Windows.Forms;
命名空间控制台应用程序WebBrowser
{
//按比例—https://stackoverflow.com/users/1768303/noseratio
班级计划
{
//控制台应用程序的入口点
静态void Main(字符串[]参数)
{
尝试
{
//下载每个页面并转储内容
var task=MessageLoopWorker.Run(DoWorkAsync,
"http://www.example.com", "http://www.example.net", "http://www.example.org");
task.Wait();
WriteLine(“DoWorkAsync已完成”);
}
捕获(例外情况除外)
{
Console.WriteLine(“DoWorkAsync失败:+ex.Message”);
}
控制台。WriteLine(“按Enter键退出”);
Console.ReadLine();
}
//将WebBrowser导航到循环中的URL列表
静态异步任务DoWorkAsync(对象[]args)
{
Console.WriteLine(“开始工作”);
使用(var wb=new WebBrowser())
{
wb.ScriptErrorsSuppressed=true;
TaskCompletionSource tcs=null;
WebBrowserDocumentCompletedEventHandler documentCompletedHandler=(s,e)=>
tcs.TrySetResult(真);
//导航到列表中的每个URL
foreach(参数中的变量url)
{
tcs=新任务完成源();
wb.DocumentCompleted+=documentCompletedHandler;
尝试
{
导航(url.ToString());
//等待文档完成
等待tcs任务;
}
最后
{
wb.DocumentCompleted-=documentCompletedHandler;
}
//DOM已经准备好了
Console.WriteLine(url.ToString());
Console.WriteLine(wb.Document.Body.OuterHtml);
}
}
控制台写入线(“结束工作”);
返回null;
}
}
//用于启动消息循环并执行异步任务的帮助器类
公共静态类MessageLoopWorker
{
公共静态异步任务运行(Func worker,params object[]args)
{
var tcs=new TaskCompletionSource();
变量线程=新线程(()=>
{
EventHandler idleHandler=null;
idleHandler=async(s,e)=>
{
//处理应用程序。仅空闲一次
Application.Idle-=idleHandler;
//返回到消息循环
等待任务;
//并异步继续
//提出结果或例外
尝试
{
var结果=等待工作人员(args);
tcs.SetResult(结果);
}
捕获(例外情况除外)
{
tcs.SetException(ex);
}
//退出消息循环的信号
//此时将退出Application.Run
Application.ExitThread();
};
//处理应用程序。仅空闲一次
//确保我们在消息循环中
//和SynchronizationContext已正确安装
Application.Idle+=idleHandler;
Application.Run();
});
//为新线程设置STA模型
SetApartmentState(ApartmentState.STA);
//启动线程并等待任务
thread.Start();
尝试
{
返回等待任务;
}
最后
{
thread.Join();
}
}
}
}
一种简单的解决方案,多个Web浏览器同时运行
textBox1.Clear();
textBox1.AppendText(DateTime.Now.ToString() + Environment.NewLine);
int completed_count = 0;
int count = 10;
for (int i = 0; i < count; i++)
{
int tmp = i;
this.BeginInvoke(new Action(() =>
{
var wb = new WebBrowser();
wb.ScriptErrorsSuppressed = true;
wb.DocumentCompleted += (cur_sender, cur_e) =>
{
var cur_wb = cur_sender as WebBrowser;
if (cur_wb.Url == cur_e.Url)
{
textBox1.AppendText("Task " + tmp + ", navigated to " + cur_e.Url + Environment.NewLine);
completed_count++;
}
};
wb.Navigate("https://stackoverflow.com/questions/4269800/webbrowser-control-in-a-new-thread");
}
));
}
while (completed_count != count)
{
Application.DoEvents();
Thread.Sleep(10);
}
textBox1.AppendText("All completed" + Environment.NewLine);
textBox1.Clear();
textBox1.AppendText(DateTime.Now.ToString()+Environment.NewLine);
int completed_count=0;
整数计数=10;
for(int i=0;i
{
var wb=新的WebBrowser();
wb.scriptErrors已被抑制=
textBox1.Clear();
textBox1.AppendText(DateTime.Now.ToString() + Environment.NewLine);
int completed_count = 0;
int count = 10;
for (int i = 0; i < count; i++)
{
int tmp = i;
this.BeginInvoke(new Action(() =>
{
var wb = new WebBrowser();
wb.ScriptErrorsSuppressed = true;
wb.DocumentCompleted += (cur_sender, cur_e) =>
{
var cur_wb = cur_sender as WebBrowser;
if (cur_wb.Url == cur_e.Url)
{
textBox1.AppendText("Task " + tmp + ", navigated to " + cur_e.Url + Environment.NewLine);
completed_count++;
}
};
wb.Navigate("https://stackoverflow.com/questions/4269800/webbrowser-control-in-a-new-thread");
}
));
}
while (completed_count != count)
{
Application.DoEvents();
Thread.Sleep(10);
}
textBox1.AppendText("All completed" + Environment.NewLine);