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