1 private void button1_Click(object sender, EventArgs e)
2 {
3 //報錯:從不是創建控件的線程訪問它
4 Thread t = new Thread(() =>
5 {
6 for (int i = 0; i < 100; i++)
7 {
8 this.label1.Text = i.ToString();
9 }
10 });
11 t.Start();
12 }
上面的代碼會報錯,從新的線程訪問其他線程的控件:這是因為.NET禁止了跨線程調用控件, 否則誰都可以操作控件,最後可能造成錯誤。
(百度答案)從程序設計上來說,只有創建界面的主線程才能訪問界面上的控件,所以會出錯.
當然,設置CheckForIllegalCrossThreadCalls =false 是能去掉這個檢查的,但是這不是標准的作法.
標准的作法是在訪問界面控件時,訪問下窗體的 InvokeRequired 屬性,如果為false就可以直接訪問,否則就是跨線程訪問;此時,創建一個delegate,並通過Invoke() 來調用它.
1 private void button1_Click(object sender, EventArgs e)
2 {
3 //線程的依附性:只有創建某些對象的線程、才能訪問它所創建的某些對象
4 //解決跨線程調用的問題,可以采用封送(Marshal) .調用Invoke方法
5 //使用封送
6 new Thread(() =>
7 {
8 for (int i = 0; i < 10000; i++)
9 {
10 Action<int> action = (data) =>
11 {
12 this.label1.Text = data.ToString(); };
13 Invoke(action,i);
14 }
15 }).Start();
16 //MessageBox 沒有遵循依附性的原則,所以可以在工作線程中直接訪問
17 }
2.1 我們將Action轉到定義發現
1 namespace System
2 {
3 // 摘要:
4 // 封裝一個方法,該方法只有一個參數並且不返回值。
5 //
6 // 參數:
7 // obj:
8 // 此委托封裝的方法的參數。
9 //
10 // 類型參數:
11 // T:
12 // 此委托封裝的方法的參數類型。
13 public delegate void Action<in T>(T obj);
14 }
2.2 Action是個委托:那麼我們自己來寫個委托(對於自己未掌握的知識,我習慣用自己寫的代碼)
1 //申明一個委托對象
2 public delegate void Action2<in T>(T t);
3 private void button1_Click(object sender, EventArgs e)
4 {
5 new Thread(() =>
6 {
7 for (int i = 0; i < 10000; i++)
8 {
9 Action2<int> a = new Action2<int>(Action2Test);
10 Invoke(a, i);
11 }
12 }).Start();
13
14 }
15 public void Action2Test(int t)
16 {
17 this.label1.Text = t.ToString();
18 }
2.3 看代碼得知:我們用了委托來完成的任務。那麼委托是怎麼玩成任務的?
(因為包含一些底層什麼API我不懂的知識,簡單說下自己的理解):委托將方法傳到控件所在線程的委托或方法由它執行