UI线程以外的线程不能直接更新UI界面,那如何在工作线程中更新UI界面呢?
invoke和beginInvoke的出现是为了解决跨线程更新UI显示的问题,invoke是同步的执行,而beginInvoke是异步执行的,不会阻塞后面的代码,但如果使用了endInvoke监听的话同样会阻塞后面代码,此时的作用相当于invoke。
此处以一个10秒走表例子来说明问题
一、阻塞UI线程方法
private void button1_Click(object sender, EventArgs e)
{
for (int i = 1; i <=10;i++)
{
Thread.Sleep(1000);
lblSecond.Text = i.ToString();//主线程会卡死
}
}
二、创建新线程执行任务,并用control.Invoke更新UI显示
private void button2_Click(object sender, EventArgs e)
{
Thread myThread = new Thread(new ThreadStart(ShowSecond));
myThread.Start();
}
private delegate void showSecondDelegate();//定义一个委托
private void ShowSecond()
{
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(1000);
this.Invoke(new showSecondDelegate(delegate() //在委托方法中更新UI控件值
{
lblSecond.Text = i.ToString(); //如果将thread.sleep放到此处,则会阻塞主线程,因为此处运行在主线程上
}));
//后面的代码 //后面的代码会等invoke委托方法执行完成后再执行
//...
}
}
三、创建新线程执行任务,并用control.BeginInvoke更新UI显示
private void button3_Click(object sender, EventArgs e)
{
Thread myThread = new Thread(ShowSecond1);
myThread.Start();
}
private delegate void showSecondDelegate1();
private void ShowSecond1()
{
for (int i = 1; i <= 10; i++)
{
this.BeginInvoke(new showSecondDelegate1(delegate()
{
MessageBox.Show(i.ToString());
lblSecond.Text = i.ToString();
}));
//后面的代码 //后面的代码会立即执行,不会等BeginInvoke委托方法执行完成后再执行
//...
}
}
四、创建新线程执行任务,并用control.BeginInvoke更新UI显示,使用control.EndInvoke监听结果,并阻塞当前线程
private delegate bool showSecondDelegate2();
/// <summary>
/// 异步(beginInvoke更新UI-阻塞工作线程)
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void button4_Click(object sender, EventArgs e)
{
Thread myThread = new Thread(ShowSecond2);
myThread.Start();
}
private void ShowSecond2()
{
for (int i = 1; i <= 10; i++)
{
Thread.Sleep(1000);
IAsyncResult iasync = this.BeginInvoke(new showSecondDelegate2(delegate()
{
lblSecond.Text = i.ToString();
return true;
}));
object result = this.EndInvoke(iasync); //监听BeginInvoke委托方法执行结果,阻塞后面代码执行,直到委托方法执行完成
//后面的代码
//...
} }
总结:
1、invoke和beginInvoke委托方法依然运行在主线程中,而不是当前线程,使用thread.sleep照样会阻塞主线程,所以耗时的操作应该放在工作线程中执行,更新UI显示
相关的代码放在委托方法中
2、在工作线程中想异步更新UI界面显示的话用beginInvoke,不影响后面代码运行