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控件的窗口,
实现多线程加速,
如果一个网页崩溃,不会导致整个程序关闭。
源码下载:http://files.cnblogs.com/kofip/WebBrowserTest.rar
简化后源码:http://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