首先將如下代碼放到Button事件裏面:多線程
private void btnStart_Click(object sender, EventArgs e)
{
for (int q = 0; q < 100000; q++)
{
textBox1.Text = q.ToString();
}
}this
你會發現當點擊Start按鈕後,循環會一直進行,此時窗體會出現假死的狀態,如:沒法拖動。直到循環結束,textBox1中才會顯示出結果。如何解決窗體的假死狀態??spa
修改以上代碼以下:線程
private void btnStart_Click(object sender, EventArgs e)
{
for (int q = 0; q < 100000; q++)
{
textBox1.Text = q.ToString();
//實時響應文本框中的值
Application.DoEvents();
}
}orm
此時再次點擊Start按鈕後,textBox中的數字會不斷改變,同時,你也能夠拖動窗體。。。blog
可是這樣使用Application.DoEvents()好嗎?若是用多線程來實現相同的效果呢?事件
多線程實現代碼以下: it
public Form1()
{
InitializeComponent();
//不捕獲跨線程調用引發的異常
CheckForIllegalCrossThreadCalls = false;
}
private void btnStart_Click(object sender, EventArgs e)
{
Thread s1 = new Thread(new ThreadStart(ThreadMeth));
s1.Start();
}
public void ThreadMeth()
{
for (int q = 0; q < 100000; q++)
{io
textBox1.Text = q.ToString();
}
}object
注意:Form1()裏面添加了一行代碼,解決跨線程調用產生的異常。
以上代碼和使用Application.DoEvents()達到相同的效果。
下面咱們來比較一下,使用Application.DoEvents()和使用多線程哪一個更耗時?
代碼以下:
public void ThreadMeth()
{
label1.Text = DateTime.Now.ToString();
for (int q = 0; q < 100000; q++)
{
textBox1.Text = q.ToString();
}
label5.Text = DateTime.Now.ToString();
}
private void btnStartDo_Click(object sender, EventArgs e)
{
label3.Text = DateTime.Now.ToString();
for (int q = 0; q < 100000; q++)
{
textBox2.Text = q.ToString();
Application.DoEvents();//實時響應文本框中的值
}
label6.Text = DateTime.Now.ToString();
}
(假設以上比較時間的代碼處在正確的位置)由此可知,Application.DoEvents()消耗的時間更少,但這裏並不建議使用Application.DoEvents(),由於它會引發不少未知的錯誤。
補充:因爲顯示的定義 CheckForIllegalCrossThreadCalls = false;並非好的方法,下面來改進一下,以下:
int i;
private void btnStart_Click(object sender, EventArgs e)
{
Thread s1 = new Thread(new ThreadStart(ThreadMeth));
s1.Start();
}
private void ThreadMeth()
{
for ( i = 0; i < 100000; i++)
{
MethodInvoker mi = new MethodInvoker(Count);
this.Invoke(mi);
//BeginInvoke(mi);
}
}
private void Count()
{
textBox1.Text = i.ToString();
}
MethodInvoker實質上是一個委託,查看其定義可知...
using System;
namespace System.Windows.Forms
{
// 表示一個委託,該委託可執行託管代碼中聲明爲 void 且不接受任何參數的任何方法。
public delegate void MethodInvoker();
}
以上用匿名委託的方式彷佛更簡潔,代碼以下:
private void btnStart_Click(object sender, EventArgs e)
{
new Thread((ThreadStart)(delegate()
{
for (int i = 0; i < 10000; i++)
{
label1.Invoke((MethodInvoker)delegate()
{
textBox1.Text = i.ToString();
});
};
})) .Start();
}
在次線程上計算,在主線程上調用label。