Invoke和BeginInvoke
在C#中,Invoke
和 BeginInvoke
是 .NET Framework 中用于解决多线程环境下的用户界面(UI)更新问题的方法,通常用于Windows Forms和WPF应用程序中。这些方法主要用于从非UI线程访问或修改UI线程上的控件属性或调用方法,因为Windows应用程序要求所有的UI操作必须在创建它们的同一个线程(即UI线程)上执行。
1.Invoke
Control.Invoke
或Dispatcher.Invoke
(在WPF中)方法允许开发者在UI线程上调用指定的委托方法。当在一个非UI线程上调用Invoke
时,Invoke
会请求排队,并等待UI线程执行完这个方法之后返回。-
if (this.InvokeRequired)//判断是否是UI线程 { this.Invoke(new Action(() => { textBox.Text = "更新文本"; })); } else { textBox.Text = "更新文本"; }
- 注:
this.InvokeRequired
属性是 .NET 框架中 Windows 窗体控件(对于 WPF 则是 DispatcherObject 类)的一个成员,用来检测当前代码是否在创建该控件的 UI 线程上运行,在非 UI 线程上调用此属性,则返回true
。在这个例子中,如果不在UI线程,this.InvokeRequired
则为true,通过Invoke
安全地更新文本框的内容。
2.BeginInvoke
Control.BeginInvoke
或Dispatcher.BeginInvoke
是异步版本,它同样在UI线程上调度委托方法的执行,但不同的是,它立即返回,不阻塞调用它的线程。- 异步调用示例:
-
if (this.InvokeRequired)//判断是否是UI线程 { this.BeginInvoke(new Action(() => { textBox.Text = "异步更新文本"; })); } else { textBox.Text = "异步更新文本"; }
- 在这段代码中,即使在非UI线程上,也能够发起对UI元素的更新请求,然后立即返回,不影响当前线程的其他任务执行。
总结一下 Invoke
和 BeginInvoke
的主要区别:
- 同步/异步:
Invoke
是同步调用,会阻塞调用线程直到操作完成;BeginInvoke
是异步调用,调用后立即返回,不等待操作完成。 - 阻塞行为: 使用
Invoke
时,调用线程会等待UI更新完成;使用BeginInvoke
时,调用线程不会等待,可以继续执行后续代码。
两者都是为了保证线程安全的UI更新,选择哪个取决于具体的应用场景,是否需要等待UI更新完成,以及是否有性能和响应速度上的考量。