C#-Control.Invoke与Control.BeginInvoke

我们有时会从其他的线程去更新我们的控件,Control的创建是在UI线程中的,所以对Control的更新也必须在UI线程中,确切地说应该是谁负责创建Control,就在此线程中进行更新.其它线程直接去修改会抛异常,必须通过Control.Invoke或者Control.BeginInvoke来进行调用更新,这样看来其实Control.Invoke与Control.BeginInvoke的功能就是为了切换线程,以此达到线程的安全访问。

控件上的大多数方法只能从创建控件的线程调用。 如果已经创建控件的句柄,则除了 InvokeRequired 属性以外,控件上还有四个可以从任何线程上安全调用的方法,它们是:Invoke、BeginInvoke、EndInvoke 和 CreateGraphics。 在后台线程上创建控件的句柄之前调用 CreateGraphics 可能会导致非法的跨线程调用。 对于所有其他方法调用,则应使用调用 (invoke) 方法之一封送对控件的线程的调用。 调用方法始终在控件的线程上调用自己的回调。

那么Control.Invoke与Control.BeginInvoke有什么区别呢?先来测试一下

private void button1_Click(object sender, EventArgs e)
{
    string ThreadID = "CurrentThreadID : " + Thread.CurrentThread.ManagedThreadId.ToString() + "\n";
    richTextBox.AppendText(ThreadID);
    richTextBox.AppendText("------Begin------\n");
    richTextBox.Invoke(new Action(() =>
    {
        ThreadID = "CurrentThreadID : " + Thread.CurrentThread.ManagedThreadId.ToString() + "\n";
        richTextBox.AppendText(ThreadID);
        richTextBox.AppendText("Invoke\n");
    })); 
    richTextBox.AppendText("------End------\n");
}

打印的结果

CurrentThreadID : 9
------Begin------
CurrentThreadID : 9
Invoke
------End------

从结果可以看出,我们点击鼠标时的线程(UI线程)和richTextBox.Invoke中委托执行的线程是同一个,这说明richTextBox.Invoke中的方法是在UI线程中运行的,而且还是顺序执行的。那么Control.BeginInvoke呢?

private void button1_Click(object sender, EventArgs e)
{
       string ThreadID = "CurrentThreadID : " + Thread.CurrentThread.ManagedThreadId.ToString() + "\n";
       richTextBox.AppendText(ThreadID);
       richTextBox.AppendText("------Begin------\n");
       richTextBox.BeginInvoke(new Action(() =>
       {
           ThreadID = "CurrentThreadID : " + Thread.CurrentThread.ManagedThreadId.ToString() + "\n";
           richTextBox.AppendText(ThreadID);
           richTextBox.AppendText("BeginInvoke\n");
       }));
       Thread.Sleep(1000);
       richTextBox.AppendText("------End------\n");
}

执行的结果

CurrentThreadID : 9
------Begin------
------End------
CurrentThreadID : 9
BeginInvoke

从结果可以看出,我们点击鼠标时的线程(UI线程)和richTextBox.BeginInvoke中委托执行的线程是同一个,这说明richTextBox.BeginInvoke中的方法是在UI线程中运行的,但却是最后执行BeginInvoke中的方法。虽然说不上异步,但是却是在button1_Click方法执行完之后才开始执行的。如果我们有一个长时间的工作,想通过Control.Invoke与Control.BeginInvoke来执行,只是万万不可的,因为Control.Invoke与Control.BeginInvoke中的方法还是执行在UI线程中的,这样还是会阻碍界面的响应。

你可能感兴趣的:(C#-Control.Invoke与Control.BeginInvoke)