線程編程 線程間操作無效: 從不是建立控制項的線程訪問它

來源:互聯網
上載者:User
線程間操作無效: 從不是建立控制項的線程訪問它 

 訪問 Windows 表單控制項本質上不是安全執行緒的。如果有兩個或多個線程操作某一控制項的狀態,則可能會迫使該控制項進入一種不一致的狀態。還可能出現其他與線程相關的 bug,包括爭用情況和死結。確保以安全執行緒方式訪問控制項非常重要。

.NET Framework 有助於在以非安全執行緒方式訪問控制項時檢測到這一問題。在調試器中運行應用程式時,如果建立某控制項的線程之外的其他線程試圖調用該控制項,則調試器會引發一個 InvalidOperationException,並提示訊息:“從不是建立控制項 control name 的線程訪問它。”

此異常在調試期間和運行時的某些情況下可靠地發生。強烈建議您在顯示此錯誤資訊時修複此問題。在調試以 .NET Framework 2.0 版之前的 .NET Framework 編寫的應用程式時,可能會出現此異常。
注意
可以通過將 CheckForIllegalCrossThreadCalls 屬性的值設定為 false 來禁用此異常。這會使控制項以與在 Visual Studio 2003 下相同的方式運行。

下面的程式碼範例示範如何從輔助線程以安全執行緒方式和非安全執行緒方式調用 Windows 表單控制項。它示範一種以非安全執行緒方式設定 TextBox 控制項的 Text 屬性的方法,還示範兩種以安全執行緒方式設定 Text 屬性的方法。

view plaincopy to clipboardprint?
  1. using System;  
  2. using System.ComponentModel;  
  3. using System.Threading;  
  4. using System.Windows.Forms;  
  5. namespace CrossThreadDemo  
  6. {  
  7. public class Form1 : Form  
  8. {  
  9. // 代理實現非同步呼叫以設定TextBox控制項text屬性  
  10. delegate void SetTextCallback(string text);  
  11. // 此線程用來示範安全執行緒和非安全兩種方式來調用一個windows表單控制項  
  12. private Thread demoThread = null;  
  13. // 此後台工作者(BackgroundWorker)用來示範執行非同步作業的首選方式  
  14. private BackgroundWorker backgroundWorker1;  
  15. private TextBox textBox1;  
  16. private Button setTextUnsafeBtn;  
  17. private Button setTextSafeBtn;  
  18. private Button setTextBackgroundWorkerBtn;  
  19. private System.ComponentModel.IContainer components = null;  
  20. public Form1()  
  21. {  
  22. InitializeComponent();  
  23. }  
  24. protected override void Dispose(bool disposing)  
  25. {  
  26. if (disposing && (components != null))  
  27. {  
  28. components.Dispose();  
  29. }  
  30. base.Dispose(disposing);  
  31. }  
  32. // 此事件控制代碼建立一個ie線程以非安全方式調用一個windows表單控制項  
  33. private void setTextUnsafeBtn_Click(  
  34. object sender,  
  35. EventArgs e)  
  36. {  
  37. this.demoThread =  
  38. new Thread(new ThreadStart(this.ThreadProcUnsafe));  
  39. this.demoThread.Start();  
  40. }  
  41. // 此方法在工作者線程執行並且對TextBox控制項作非安全調用  
  42. private void ThreadProcUnsafe()  
  43. {  
  44. this.textBox1.Text = "This text was set unsafely.";  
  45. }  
  46. // 此事件控制代碼建立一個以安全執行緒方式調用windows表單控制項的線程  
  47. private void setTextSafeBtn_Click(  
  48. object sender,  
  49. EventArgs e)  
  50. {  
  51. this.demoThread =  
  52. new Thread(new ThreadStart(this.ThreadProcSafe));  
  53. this.demoThread.Start();  
  54. }  
  55. // 此方法在工作者線程執行並且對TextBox控制項作安全執行緒調用  
  56. private void ThreadProcSafe()  
  57. {  
  58. this.SetText("This text was set safely.");  
  59. }  
  60. // 此方法示範一個對windows表單控制項作安全執行緒調用的模式  
  61. //  
  62. // 如果調用線程和建立TextBox控制項的線程不同,這個方法建立  
  63. // 代理SetTextCallback並且自己通過Invoke方法非同步呼叫它  
  64. // 如果相同則直接設定Text屬性  
  65. private void SetText(string text)  
  66. {  
  67. // InvokeRequired需要比較調用線程ID和建立線程ID  
  68. // 如果它們不相同則返回true  
  69. if (this.textBox1.InvokeRequired)  
  70. {  
  71. SetTextCallback d = new SetTextCallback(SetText);  
  72. this.Invoke(d, new object[] { text });  
  73. }  
  74. else  
  75. {  
  76. this.textBox1.Text = text;  
  77. }  
  78. }  
  79. // 此事件控制代碼通過調用RunWorkerAsync開啟表單的BackgroundWorker  
  80. //  
  81. // 當BackgroundWorker引發RunworkerCompleted事件的時候TextBox  
  82. // 控制項的Text屬性被設定  
  83. private void setTextBackgroundWorkerBtn_Click(  
  84. object sender,  
  85. EventArgs e)  
  86. {  
  87. this.backgroundWorker1.RunWorkerAsync();  
  88. }  
  89. // 此事件控制代碼設定TextBox控制項的Text屬性,它在建立TextBox控制項的線程  
  90. // 中被調用,所以它的調用是安全執行緒的  
  91. //  
  92. // BackgroundWorker是執行非同步作業的首選方式  
  93. private void backgroundWorker1_RunWorkerCompleted(  
  94. object sender,  
  95. RunWorkerCompletedEventArgs e)  
  96. {  
  97. this.textBox1.Text =  
  98. "This text was set safely by BackgroundWorker.";  
  99. }  
  100. #region Windows Form Designer generated code  
  101. private void InitializeComponent()  
  102. {  
  103. this.textBox1 = new System.Windows.Forms.TextBox();  
  104. this.setTextUnsafeBtn = new System.Windows.Forms.Button();  
  105. this.setTextSafeBtn = new System.Windows.Forms.Button();  
  106. this.setTextBackgroundWorkerBtn = new System.Windows.Forms.Button();  
  107. this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();  
  108. this.SuspendLayout();  
  109. //  
  110. // textBox1  
  111. //  
  112. this.textBox1.Location = new System.Drawing.Point(12, 12);  
  113. this.textBox1.Name = "textBox1";  
  114. this.textBox1.Size = new System.Drawing.Size(240, 20);  
  115. this.textBox1.TabIndex = 0;  
  116. //  
  117. // setTextUnsafeBtn  
  118. //  
  119. this.setTextUnsafeBtn.Location = new System.Drawing.Point(15, 55);  
  120. this.setTextUnsafeBtn.Name = "setTextUnsafeBtn";  
  121. this.setTextUnsafeBtn.TabIndex = 1;  
  122. this.setTextUnsafeBtn.Text = "Unsafe Call";  
  123. this.setTextUnsafeBtn.Click += new System.EventHandler(this.setTextUnsafeBtn_Click);  
  124. //  
  125. // setTextSafeBtn  
  126. //  
  127. this.setTextSafeBtn.Location = new System.Drawing.Point(96, 55);  
  128. this.setTextSafeBtn.Name = "setTextSafeBtn";  
  129. this.setTextSafeBtn.TabIndex = 2;  
  130. this.setTextSafeBtn.Text = "Safe Call";  
  131. this.setTextSafeBtn.Click += new System.EventHandler(this.setTextSafeBtn_Click);  
  132. //  
  133. // setTextBackgroundWorkerBtn  
  134. //  
  135. this.setTextBackgroundWorkerBtn.Location = new System.Drawing.Point(177, 55);  
  136. this.setTextBackgroundWorkerBtn.Name = "setTextBackgroundWorkerBtn";  
  137. this.setTextBackgroundWorkerBtn.TabIndex = 3;  
  138. this.setTextBackgroundWorkerBtn.Text = "Safe BW Call";  
  139. this.setTextBackgroundWorkerBtn.Click +=  
  140.     new System.EventHandler(this.setTextBackgroundWorkerBtn_Click);  
  141. // backgroundWorker1  
  142. //  
  143. this.backgroundWorker1.RunWorkerCompleted +=  
  144.      new System.ComponentModel.RunWorkerCompletedEventHandler(  
  145.        this.backgroundWorker1_RunWorkerCompleted);  
  146. //Form1  
  147. this.ClientSize = new System.Drawing.Size(268, 96);  
  148. this.Controls.Add(this.setTextBackgroundWorkerBtn);  
  149. this.Controls.Add(this.setTextSafeBtn);  
  150. this.Controls.Add(this.setTextUnsafeBtn);  
  151. this.Controls.Add(this.textBox1);  
  152. this.Name = "Form1";  
  153. this.Text = "Form1";  
  154. this.ResumeLayout(false);  
  155. this.PerformLayout();  
  156. }  
  157. #endregion  
  158. [STAThread]  
  159. static void Main()  
  160. {  
  161. Application.EnableVisualStyles();  
  162. Application.Run(new Form1());  
  163. }  
  164. }  

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.