在窗體程序中我們常把費時操作另開新線程,但是我們要知道新線程的運行狀態,又要對UI線程進行操作來顯示新線程狀態;例如:
C#代碼
namespace CrossCall
{
public partial class Form1 : Form
{
Thread thread = null;
public Form1()
{
InitializeComponent();
//CheckForIllegalCrossThreadCalls = false;
thread = new Thread(fun);
thread.Start();//啟用新線程
}
private void fun()
{
int i = 10;
while (i-- > 0)
{
label1.Text = i.ToString();//在新線程中更新UI控件
Thread.Sleep(1000);
}
}
//如果程序關閉後線程還在運行,則關閉線程
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (thread != null)
{
thread.Abort();
}
}
}
}
這時程序運行就發生錯誤了:
這種錯誤我一般用以下兩種方法解決:
1.對於那種明知道跨線程調用不會帶來錯誤的,可以設置Form控件不檢查跨線程調用錯誤,這樣就不報錯了。
在Form1構造方法中:
C#代碼
CheckForIllegalCrossThreadCalls = false;
2.但是,為了防止多個線程同時更新控件造成錯誤,也可以采用代理的方法:
Control .BeginInvoke 方法 (Delegate)在創建控件的基礎句柄所在線程上異步執行指定委托。
這是幫助文檔的例子:
C#代碼
public delegate void InvokeDelegate();
private void Invoke_Click(object sender, EventArgs e)
{
myTextBox.BeginInvoke(new InvokeDelegate(InvokeMethod));
}
public void InvokeMethod()
{
myTextBox.Text = "Executed the given delegate";
}
如果我們不像自己去寫委托,可以使用MethodInvoker 委托:
MethodInvoker 提供一個簡單委托,該委托用於調用含 void 參數列表的方法。 在對控件的 Invoke 方法進行調用時或需要一個簡單委托又不想自己定義時可以使用該委托。
所以,代碼可改寫為:
C#代碼
namespace CrossCall
{
public partial class Form1 : Form
{
Thread thread = null;
public Form1()
{
InitializeComponent();
//CheckForIllegalCrossThreadCalls = false;
thread = new Thread(fun);
thread.Start();//啟用新線程
}
private void fun()
{
int i = 10;
while (i-- > 0)
{
//label1.Text = i.ToString();//在新線程中更新UI控件
BeginInvoke(new MethodInvoker(delegate()
{
label1.Text = i.ToString();//在新線程中更新UI控件
}));
Thread.Sleep(1000);
}
}
//如果程序關閉後線程還在運行,則關閉線程
private void Form1_FormClosed(object sender, FormClosedEventArgs e)
{
if (thread != null)
{
thread.Abort();
}
}
}
}
程序正常執行。