背景:在winform UI中,有时需要对控件进行比较频繁的刷新,如进度条、picturebox显示视频等。如果在主线程进行这些刷新操作,操作还未完成就将执行下一次刷新,程序将发生错误;如果只是创建另一个线程执行这些操作,将和主线程产生竞争,造成界面锁死(因此windows GUI编程有一个规则,就是只能通过创建控件的线程来操作控件的数据,否则就可能产生不可预料的结果)。这时候,我们就可以用委托与异步来解决这个问题。
委托:回顾一下委托 ,一、定义委托,委托定义的参数与传递给委托的方法的参数一致。二、声明与实例化。三、调用,将委托作为参数供方法调用。
异步:Windows窗体控件,唯一可以从创建它的线程之外的线程中调用的是Invoke()、BeginInvoke()、EndInvoke()方法和InvokeRequired属性。这些方法会切换到创建控件的线程上,以调用赋予一个委托参数的方法,该委托参数可以传递给这些方法。
关于Invoke()与BeginInvoke():其中BeginInvoke()、EndInvoke()方法是Invoke()方法的异步版本。相同点:都需要一个委托对象作为参数。不同点:Invoke()是同步方法,Invoke封送的方法被执行完毕前,Invoke()不会返回,从而调用者线程将被阻塞;需要等待UI操作执行完毕后继续执行线程时考虑使用。而BeginInvoke()相反,是异步方法,方法调后立即返回,不用等待委托方法的执行结束,主线程就不会阻塞。
Delegate.BeginInvoke方法从ThreadPool取出一个线程来执行这个方法,以获得异步执行效果。Control.BeginInvoke方法并不会另开线程。
参考:http://blog.csdn.net/stxyc/article/details/16945581
初学C#,理解的不是很透彻,一步一步来,循序渐进。
下面是一个进度条的小程序:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms; namespace progressBar
{
public partial class Form1 : Form
{
delegate void ShowProgressDelegate();
delegate void RunTaskDelegate(); public Form1()
{
InitializeComponent(); this.progressBar1.Maximum = ;
this.progressBar1.Step = ;
} private void startBtn_Click(object sender, EventArgs e)
{
RunTaskDelegate runTask = new RunTaskDelegate(RunTask);
// 委托异步调用方法
runTask.BeginInvoke(null, null);
} private void closeBtn_Click(object sender, EventArgs e)
{
this.Close();
} //进度条增加
void ShowProgress()
{
this.progressBar1.PerformStep();
} //模拟工作方法
public void RunTask()
{
ShowProgressDelegate showProgress = new ShowProgressDelegate(ShowProgress); int iTotal = ;//工作量
for (int i = ; i < iTotal; i++)
{
System.Threading.Thread.Sleep();//模拟工作
this.BeginInvoke(showProgress);
}
} }
}
我目前的理解是:RunTaskDelegate的作用是从另一个线程调用RunTask()方法(此方法中包含主线程的休眠),可以避免休眠期间界面无响应。ShowProgressDelegate的作用就是异步调用ShowProgress()方法,从而避免非UI线程操作控件产生的异常。