1. 程式人生 > 其它 >執行緒訪問UI控制元件和Control.CheckForIllegalCrossThreadCalls屬性

執行緒訪問UI控制元件和Control.CheckForIllegalCrossThreadCalls屬性

技術標籤:C#說明

概況:

多執行緒程式中,新建立的執行緒不能訪問UI執行緒建立的視窗控制元件,這時如果想要訪問視窗的控制元件,發現無法對其控制。這時可將視窗建構函式中的CheckForIllegalCrossThreadCalls設定為false;然後就能安全的訪問窗體控制元件。如果捕獲了對錯誤執行緒的呼叫,則為true;否則為false。System.Windows.Forms.Control.CheckForIllegalCrossThreadCalls = false;程式初始化時設定這個屬性,再使用微軟Framework類庫中的控制元件,系統將不會再丟擲你執行緒的異常資訊。

引用方法:

private void Form1_Load(object sender, EventArgs e)
        {
            CheckForIllegalCrossThreadCalls = false;
        }

C#的Winform開發中,一般是不推薦使用執行緒去直接訪問UI控制元件的。

訪問 Windows 窗體控制元件本質上不是執行緒安全的。如果有兩個或多個執行緒操作某一控制元件的狀態,則可能會迫使該控制元件進入一種不一致的狀態。還可能出現其他與執行緒相關的 bug,包括爭用情況和死鎖。但是有時在程式編寫的時候寫了一些執行緒直接訪問UI控制元件的程式碼,執行時也不會報錯,就以為這樣做是可以的。比如下面的程式碼,定義一個執行緒,並且在執行是訪問進度條控制元件。執行程式碼後發現,一切都ok,沒有任何異常丟擲。

private void button1_Click(object sender, EventArgs e) 
{ 
            Thread t = new Thread(() => 
            { 
                try 
                { 
                    for (int i = 1; i <= 100; i++) 
                    { 
                        progressBar1.Value = i; 
                        Thread.Sleep(100); 
                    } 
                } 
                catch (Exception ex) 
                { 
                    MessageBox.Show(ex.Message); 
                } 
            }); 
            t.Start(); 
} 

但是在除錯的時候,卻會捕獲一個異常InvalidOperationException,並提示訊息:“執行緒間操作無效,從不是建立控制元件的執行緒訪問它。”這點困惑了很多人。其實這一切都是和Control.CheckForIllegalCrossThreadCalls有關。注意: Control.CheckForIllegalCrossThreadCalls屬性是在 .NET Framework 2.0 版中新增的。它的作用是獲取或設定一個值,該值指示是否捕獲對錯誤執行緒的呼叫。如果設為true則會捕獲對錯誤執行緒的呼叫,反之亦反。

如果一個執行緒並沒有建立控制元件A而去訪問控制元件A,有時候會很幸運沒什麼錯誤,但是在一些複雜的情況下會導致不可以預料的錯誤。因此將 CheckForIllegalCrossThreadCalls 設定為 true 可以更容易地查詢並診斷此執行緒活動。CheckForIllegalCrossThreadCalls會在Control類的靜態構造方法中呼叫如下的語句,Debugger.IsAttached的值表示偵錯程式是否附到程序中:

static Control() 
{ 
    //... 
    checkForIllegalCrossThreadCalls = Debugger.IsAttached; 
    //... 
} 

因此,當debug的時候,控制元件的checkForIllegalCrossThreadCalls是true。但是執行的時候checkForIllegalCrossThreadCalls是false。

我們可以手動的設定該值,以此控制是否需要捕獲異常。如下的程式碼:

public partial class Form1 : Form 
   { 
       public Form1() 
       { 
           InitializeComponent(); 
       } 
 
       private void Form1_Load(object sender, EventArgs e) 
       { 
           showCurrentCheckForIllegalCrossThreadCallsValue(); 
       } 
 
       private void button1_Click(object sender, EventArgs e) 
       { 
           Thread t = new Thread(() => 
           { 
               try 
               { 
                   for (int i = 1; i <= 100; i++) 
                   { 
                       progressBar1.Value = i; 
                       Thread.Sleep(100); 
                   } 
               } 
               catch (Exception ex) 
               { 
                   MessageBox.Show(ex.Message); 
               } 
           }); 
           t.Start(); 
       } 
 
       private void showCurrentCheckForIllegalCrossThreadCallsValue() 
       { 
           label1.Text = "ProgressBar's CheckForIllegalCrossThreadCalls Value:" + ProgressBar.CheckForIllegalCrossThreadCalls.ToString(); 
       } 
 
       private void button2_Click(object sender, EventArgs e) 
       { 
           ProgressBar.CheckForIllegalCrossThreadCalls = true; 
           showCurrentCheckForIllegalCrossThreadCallsValue(); 
       } 
 
       private void button3_Click(object sender, EventArgs e) 
       { 
           ProgressBar.CheckForIllegalCrossThreadCalls = false; 
           showCurrentCheckForIllegalCrossThreadCallsValue(); 
       } 
   } 

程式執行的時候(非除錯),ProcessBar當前的CheckForIllegalCrossThreadCalls為False,手動設定為True後,再呼叫執行緒訪問UI,得到了異常。

參考:

1、CHECKFORILLEGALCROSSTHREADCALLS = FALSE

2、執行緒訪問UI控制元件和Control.CheckForIllegalCrossThreadCalls屬性