首先我们要清楚Delegate.Invoke/BeginInvoke和Control.Invoke/BeginInvoke是不同的,他们的区别,简单理解如下:
在这里,我们重点讨论的是Control中的Invoke/BeginInvoke的区别。
上面的表述不好理解(这也是MSDN翻译成中文的通病),下面我们通过代码,查看一下执行Invoke的线程:
private void Button1_Click(object sender, EventArgs e)
{
InvokeThreadName();
}
private void InvokeThreadName()
{
Thread.CurrentThread.Name = "UIThread";
Thread th = new Thread(CallInvoke)
{
Name = "InvokeThreadName",
IsBackground=true
};
th.Start();
}
private void CallInvoke()
{
this.Invoke(new Action(PrintCurrentThread));
}
在调试的输出界面中输出:
UIThread
因此,虽然我们通过其他线程调用窗体的的Invoke方法,但是invoke方法里面的代码依然是通过UI线程执行的。
下面我们在查看执行BeginInvoke的线程:
private void Button1_Click(object sender, EventArgs e)
{
//InvokeThreadName();
BeginInvokeThreadName();
}
private void BeginInvokeThreadName()
{
Thread.CurrentThread.Name = "UIThread";
Thread th = new Thread(CallBeginInvoke)
{
Name = "BeginInvokeThreadName"
};
th.Start();
}
private void CallBeginInvoke()
{
this.BeginInvoke(new Action(PrintCurrentThread));
}
private void PrintCurrentThread()
{
Console.WriteLine(Thread.CurrentThread.Name);
}
在调试的输出界面中输出依然是:
UIThread
也就是说BeginInvoke方法里面的代码也是通过UI线程执行的。
既然都是在UI线程中执行的,那么Invoke和BeginInvoke到底有什么区别了?
我们通过代码查看一下Invoke代码的执行顺序:
private void Button1_Click(object sender, EventArgs e)
{
//InvokeThreadName();
//BeginInvokeThreadName();
TestInvoke();
}
private void TestInvoke()
{
Console.WriteLine("开始");
Thread th = new Thread(CallBeginInvoke)
{
Name = "BeginInvokeThreadName"
};
th.Start();
Console.WriteLine("结束");
}
private void TestInvokeMethod()
{
this.Invoke(new Action(() =>
{
Thread.Sleep(1000);
Console.WriteLine("这是一个耗时过程");
}));
}
在调试的输出界面中输出顺序为:
开始
这是一个耗时过程
结束
也就是说,在使用调用Invoke方法时,会阻塞UI线程,同时Invoke下面的代码需要等待Invoke内部的代码执行完之后才可以执行。
接下来我们再通过代码查看一下BeginInvoke代码的执行顺序:
private void Button1_Click(object sender, EventArgs e)
{
//InvokeThreadName();
//BeginInvokeThreadName();
//TestInvoke();
TestBeginInvoke();
}
private void TestBeginInvoke()
{
Console.WriteLine("开始");
this.BeginInvoke(new Action(() =>
{
Thread.Sleep(30000);
Console.WriteLine("这是一个耗时过程");
}));
Console.WriteLine("结束");
}
在调试的输出界面中输出顺序变为:
开始
结束
这是一个耗时过程
点击窗体上的Button按钮后,在没有输出“这是一个耗时过程”的过程中,我们无法拖动窗体的,说明在调用BeginInvoke方法时,依然会阻塞UI线程,但是它是异步执行BeginInvoke中的代码,UI线程中的代码执行顺序不受BeginInvoke的影响。