線程間操作無效:從不是創建控件“XX”的線程訪問它

在進行線程方面的編程的時,遇到這樣的錯誤 "線程間操作無效:從不是創建控件“XX”的線程訪問它"

解決方法:

在構造函數中加入如下代碼:CheckForIllegalCrossThreadCalls    =    false;

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

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

此異常在調試期間和運行時的某些情況下可靠地發生。強烈建議您在顯示此錯誤信息時修復此問題。在調試以 .NET Framework 2.0 版之前的 .NET Framework 編寫的應用程序時,可能會出現此異常。 注意 可以通過將 CheckForIllegalCrossThreadCalls 屬性的值設置爲 false 來禁用此異常。這會使控件以與在 Visual Studio 2003 下相同的方式運行。 下面的代碼示例演示如何從輔助線程以線程安全方式和非線程安全方式調用 Windows 窗體控件。它演示一種以非線程安全方式設置 TextBox 控件的 Text 屬性的方法,還演示兩種以線程安全方式設置 Text 屬性的方法。

using System;
using System.ComponentModel;
using System.Threading;
using System.Windows.Forms;
namespace CrossThreadDemo
{
public class Form1 : Form
{
// 代理實現異步調用以設置TextBox控件text屬性
delegate void SetTextCallback(string text);
// 此線程用來演示線程安全和非安全兩種方式來調用一個windows窗體控件
private Thread demoThread = null;
// 此後臺工作者(BackgroundWorker)用來演示執行異步操作的首選方式
private BackgroundWorker backgroundWorker1;
private TextBox textBox1;
private Button setTextUnsafeBtn;
private Button setTextSafeBtn;
private Button setTextBackgroundWorkerBtn;
private System.ComponentModel.IContainer components = null;
public Form1()
{
InitializeComponent();
}
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
// 此事件句柄創建一個ie線程以非安全方式調用一個windows窗體控件
private void setTextUnsafeBtn_Click(
object sender,
EventArgs e)
{
this.demoThread =
new Thread(new ThreadStart(this.ThreadProcUnsafe));
this.demoThread.Start();
}
// 此方法在工作者線程執行並且對TextBox控件作非安全調用
		private void ThreadProcUnsafe()
{
this.textBox1.Text = "This text was set unsafely.";
}
// 此事件句柄創建一個以線程安全方式調用windows窗體控件的線程
private void setTextSafeBtn_Click(
object sender,
EventArgs e)
{
this.demoThread =
new Thread(new ThreadStart(this.ThreadProcSafe));
this.demoThread.Start();
}
// 此方法在工作者線程執行並且對TextBox控件作線程安全調用
private void ThreadProcSafe()
{
this.SetText("This text was set safely.");
}
// 此方法演示一個對windows窗體控件作線程安全調用的模式
//
// 如果調用線程和創建TextBox控件的線程不同,這個方法創建
// 代理SetTextCallback並且自己通過Invoke方法異步調用它
// 如果相同則直接設置Text屬性
private void SetText(string text)
{
// InvokeRequired需要比較調用線程ID和創建線程ID
// 如果它們不相同則返回true
if (this.textBox1.InvokeRequired)
{
SetTextCallback d = new SetTextCallback(SetText);
this.Invoke(d, new object[] { text });
}
else
{
this.textBox1.Text = text;
}
}
// 此事件句柄通過調用RunWorkerAsync開啓窗體的BackgroundWorker
//
// 當BackgroundWorker引發RunworkerCompleted事件的時候TextBox
// 控件的Text屬性被設置
private void setTextBackgroundWorkerBtn_Click(
object sender,
EventArgs e)
{
this.backgroundWorker1.RunWorkerAsync();
}
// 此事件句柄設置TextBox控件的Text屬性,它在創建TextBox控件的線程
// 中被調用,所以它的調用是線程安全的
//
// BackgroundWorker是執行異步操作的首選方式
private void backgroundWorker1_RunWorkerCompleted(
object sender,
RunWorkerCompletedEventArgs e)
{
this.textBox1.Text =
"This text was set safely by BackgroundWorker.";
}
#region Windows Form Designer generated code
private void InitializeComponent()
{
this.textBox1 = new System.Windows.Forms.TextBox();
this.setTextUnsafeBtn = new System.Windows.Forms.Button();
this.setTextSafeBtn = new System.Windows.Forms.Button();
this.setTextBackgroundWorkerBtn = new System.Windows.Forms.Button();
this.backgroundWorker1 = new System.ComponentModel.BackgroundWorker();
this.SuspendLayout();
//
// textBox1
//
this.textBox1.Location = new System.Drawing.Point(12, 12);
this.textBox1.Name = "textBox1";
this.textBox1.Size = new System.Drawing.Size(240, 20);
this.textBox1.TabIndex = 0;
//
// setTextUnsafeBtn
//
this.setTextUnsafeBtn.Location = new System.Drawing.Point(15, 55);
this.setTextUnsafeBtn.Name = "setTextUnsafeBtn";
this.setTextUnsafeBtn.TabIndex = 1;
this.setTextUnsafeBtn.Text = "Unsafe Call";
this.setTextUnsafeBtn.Click += new System.EventHandler(this.setTextUnsafeBtn_Click);
//
// setTextSafeBtn
//
this.setTextSafeBtn.Location = new System.Drawing.Point(96, 55);
this.setTextSafeBtn.Name = "setTextSafeBtn";
this.setTextSafeBtn.TabIndex = 2;
this.setTextSafeBtn.Text = "Safe Call";
this.setTextSafeBtn.Click += new System.EventHandler(this.setTextSafeBtn_Click);
//
// setTextBackgroundWorkerBtn
//
this.setTextBackgroundWorkerBtn.Location = new System.Drawing.Point(177, 55);
this.setTextBackgroundWorkerBtn.Name = "setTextBackgroundWorkerBtn";
this.setTextBackgroundWorkerBtn.TabIndex = 3;
this.setTextBackgroundWorkerBtn.Text = "Safe BW Call";
this.setTextBackgroundWorkerBtn.Click +=
   new System.EventHandler(this.setTextBackgroundWorkerBtn_Click);
// backgroundWorker1
//
this.backgroundWorker1.RunWorkerCompleted +=
    new System.ComponentModel.RunWorkerCompletedEventHandler(
      this.backgroundWorker1_RunWorkerCompleted);
//Form1
this.ClientSize = new System.Drawing.Size(268, 96);
this.Controls.Add(this.setTextBackgroundWorkerBtn);
this.Controls.Add(this.setTextSafeBtn);
this.Controls.Add(this.setTextUnsafeBtn);
this.Controls.Add(this.textBox1);
this.Name = "Form1";
this.Text = "Form1";
this.ResumeLayout(false);
this.PerformLayout();
}
#endregion
[STAThread]
static void Main()
{
Application.EnableVisualStyles();
Application.Run(new Form1());
}
}
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章