Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/multithreading/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 新线程中的WebBrowser控件_C#_Multithreading_Browser - Fatal编程技术网

C# 新线程中的WebBrowser控件

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(

我有一个列表Uri,我希望单击它来实现这一点。我正在尝试为每个Uri创建一个新的web浏览器控件。我为每个Uri创建一个新线程。我遇到的问题是,线程在文档完全加载之前就结束了,所以我永远无法使用DocumentComplete事件。我如何克服这个问题

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浏览器同时运行

  • 创建新的Windows窗体应用程序
  • 放置名为的按钮 按钮1
  • 放置名为textBox1的文本框
  • 设置文本的属性 字段:多行true和滚动条
  • 写下 按钮1单击处理程序:

    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);