1 using System;
2 using System.Threading;
3 using System.Windows.Forms;
4
5 namespace WebBrowserTest
6 {
7 public partial class MainForm : Form
8 {
9 public MainForm()
10 {
11 InitializeComponent();
12 }
13
14 public static ChildForm childForm;
15
16 private void MainForm_Load(object sender, EventArgs e)
17 {
18 this.Text = string.Format("线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
19 }
20
21 private void button1_Click(object sender, EventArgs e)
22 {
23 Thread thread = new Thread(new ThreadStart(this.CreateForm));
24 thread.SetApartmentState(ApartmentState.STA);
25 thread.IsBackground = true;
26 thread.Start();
27 }
28
29 private void CreateForm()
30 {
31 MainForm.childForm = new ChildForm();
32 MainForm.childForm.webBrowser.Navigate("http://tieba.baidu.com/"); //这里不是UI线程,为什么也能导航呢?
33 MainForm.childForm.ShowDialog();
34 }
35
36 private void button2_Click(object sender, EventArgs e)
37 {
38 if (MainForm.childForm != null && MainForm.childForm.IsHandleCreated)
39 {
40 //如果不调用childForm窗口的Invoke方法修改标题,就报异常!
41 //线程间操作无效: 从不是创建控件“ChildForm”的线程访问它。
42
43 MainForm.childForm.Invoke(new MethodInvoker(delegate
44 {
45 MainForm.childForm.Text = string.Format("线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
46 }));
47
48
49
50 //为什么这里就能正常导航页面呢?
51 //难道WebBrowser控件,始终都在UI线程运行?
52 //即使创建它的线程,不是UI线程?
53
54 MainForm.childForm.webBrowser.Navigate("http://www.baidu.com/");
55 }
56 }
57 }
58 }
但是神奇的地方就是,操作WebBrowser进行网页导航,就可以不调用 Invoke 方法,不报异常。这是为什么呢?
这个环境下 WebBrowser 是运行在那个线程呢? 主线程? 还是新的子线程?
简化代码后,结果一样。
using System;
using System.Threading;
using System.Windows.Forms;
namespace WebBrowserTest
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private Form childForm;
private WebBrowser webBrowser;
private void MainForm_Load(object sender, EventArgs e)
{
this.Text = string.Format("线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(this.CreateForm));
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
}
private void CreateForm()
{
this.childForm = new Form();
this.webBrowser = new WebBrowser();
this.webBrowser.Dock = DockStyle.Fill;
this.childForm.Controls.Add(this.webBrowser);
this.webBrowser.Navigate("http://tieba.baidu.com/"); //这里不是UI线程,为什么也能导航呢?
this.childForm.ShowDialog();
}
private void button2_Click(object sender, EventArgs e)
{
if (this.childForm != null && this.childForm.IsHandleCreated)
{
//如果不调用childForm窗口的Invoke方法修改标题,就报异常!
//线程间操作无效: 从不是创建控件“ChildForm”的线程访问它。
this.childForm.Invoke(new MethodInvoker(delegate
{
this.childForm.Text = string.Format("线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
//这样修改是正常的。
}));
this.childForm.Text = "修改标题"; //这样修改就报异常了!
//为什么这里就能正常导航页面呢?
//难道WebBrowser控件,始终都在UI线程运行?
//即使创建它的线程,不是UI线程?
this.webBrowser.Navigate("http://www.baidu.com/");
}
}
}
}
此问题寻求解答,
目的:
现在多标签浏览器 它每个标签都是一个线程在执行
其中一个标签页面 崩溃 不影响到其他 标签页面
新线程创建带有WebBrowser控件的窗口,
实现多线程加速,
如果一个网页崩溃,不会导致整个程序关闭。
源码下载:https://files.cnblogs.com/kofip/WebBrowserTest.rar
简化后源码:https://files.cnblogs.com/kofip/WebBrowserTest2.rar
终于弄清楚了,.Net 1.0时代 非UI线程可以直接 操作UI控件
到了.NET 2.0开始 就不能直接操作UI控件了,
但是WebBrowser属于系统COM组件,.Net团队没有添加,检查操作线程机制。
但是实质上,也应该存在此类问题,只是他内部没有做检测罢了。
using System;
using System.Threading;
using System.Windows.Forms;
namespace WebBrowserTest
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
private Form childForm;
private WebBrowser webBrowser;
private void MainForm_Load(object sender, EventArgs e)
{
this.Text = string.Format("线程ID:{0}", Thread.CurrentThread.ManagedThreadId);
}
private void button1_Click(object sender, EventArgs e)
{
Thread thread = new Thread(new ThreadStart(this.CreateForm));
thread.SetApartmentState(ApartmentState.STA);
thread.IsBackground = true;
thread.Start();
}
private void CreateForm()
{
this.childForm = new Form();
this.webBrowser = new WebBrowser();
this.webBrowser.Dock = DockStyle.Fill;
this.webBrowser.DocumentCompleted += new WebBrowserDocumentCompletedEventHandler(this.webBrowser_DocumentCompleted);
this.childForm.Controls.Add(this.webBrowser);
//this.webBrowser.Navigate("http://tieba.baidu.com/"); //这里不是UI线程,为什么也能导航呢?
this.childForm.ShowDialog();
}
private void button2_Click(object sender, EventArgs e)
{
if (this.childForm != null && this.childForm.IsHandleCreated)
{
//如果不调用childForm窗口的Invoke方法修改标题,就报异常!
//线程间操作无效: 从不是创建控件“ChildForm”的线程访问它。
int threadId = Thread.CurrentThread.ManagedThreadId;
this.childForm.Invoke(new MethodInvoker(delegate
{
this.childForm.Text = string.Format("主线程ID:{0} 子线程ID:{1}", threadId, Thread.CurrentThread.ManagedThreadId);
//这样修改是正常的。
}));
//this.childForm.Text = "修改标题"; //这样修改就报异常了!
//为什么这里就能正常导航页面呢?
//难道WebBrowser控件,始终都在UI线程运行?
//即使创建它的线程,不是UI线程?
this.webBrowser.Navigate("http://www.baidu.com/");
}
}
private void webBrowser_DocumentCompleted(object sender, WebBrowserDocumentCompletedEventArgs e)
{
if (this.webBrowser.ReadyState == WebBrowserReadyState.Complete)
{
MessageBox.Show(string.Format("WebBrowser线程ID:{0}", Thread.CurrentThread.ManagedThreadId));
}
}
}
}
转自:http://www.cnblogs.com/kofip/archive/2012/09/24/2699477.html