winform 跨線程訪問問題


一、問題描述

進行winform 開發我們在進行數據交換時避免不了使用多線程或異步方法,這樣操作也將避免不了跨線程對控件進行操作(賦值、修改屬性)。

下面通過一個測試說明一下問題

點擊一個按鈕異步對textbox進行賦值

運行測試結果

1 private void button1_Click(object sender, EventArgs e)
2 {        
3               Action<string> action = new Action<string>((str) =>
4               {
5                   // 解決跨線程賦值
6                   this.textBox1.Text = str;              
7               });
8               action.BeginInvoke("Test", null, null);      
9 }
View Code

產生錯誤的原因:textBox1是由主線程創建的,異步方法(或子線程)是另外創建的一個線程,在.NET上執行的是托管代碼,C#強制要求這些代碼必須是線程安全的,即不允許跨線程訪問Windows窗體的控件。

二、解決方法

1.在窗體的加載事件中,將C#內置控件(Control)類的CheckForIllegalCrossThreadCalls屬性設置為false,屏蔽掉C#編譯器對跨線程調用的檢查。

1 //取消跨線程的訪問
2 Control.CheckForIllegalCrossThreadCalls = false;
View Code

使用上述的方法雖然可以保證程序正常運行並實現應用的功能,但是在實際的軟件開發中,做如此設置是不安全的(不符合.NET的安全規范),在產品軟件的開發中,此類情況是不允許的。如果要在遵守.NET安全標准的前提下,實現從一個線程成功地訪問另一個線程創建的空間,要使用C#的方法回調機制。

2.使用回調函數 ( 委托的應用 )

(1) 定義聲明回調

(2) 初始化回調

(3) 觸發動作

 1         /// <summary>
 2         /// 定義委托
 3         /// </summary>
 4         /// <param name="str"></param>
 5         private delegate void SetValueDelegate(string str);
 6 
 7         /// <summary>
 8         /// 聲明委托
 9         /// </summary>
10         SetValueDelegate test;
11 
12         /// <summary>
13         /// 回調方法
14         /// </summary>
15         /// <param name="str"></param>
16         private void SetTbValue(string str)
17         {
18             this.textBox1.Text = str;
19         }
20 
21         private void button1_Click(object sender, EventArgs e)
22         {
23             // 實例化委托    
24             test = new SetValueDelegate(SetTbValue);
25 
26             Action<string> action = new Action<string>((str) =>
27             {
28                   // 解決跨線程賦值                 
29                   this.textBox1.Invoke(test, str);
30              });
31 
32             action.BeginInvoke("Test", null, null);
33         }
View Code

我個人比較使用喜歡使用事件解決(原理同委托一樣),但省掉不少代碼

 1         private void button1_Click(object sender, EventArgs e)
 2         {
 3             Action<string> action = new Action<string>((str) =>
 4               {
 5                   // 解決跨線程賦值            
 6                   this.textBox1.Invoke(
 7                       new Action<string>((param) =>
 8                       {
 9                           this.textBox1.Text = param;
10                       }
11                       ), str);
12               });
13 
14             action.BeginInvoke("Test", null, null);
15         }
View Code

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM