C#后台线程如何告诉UI线程它已完成某些操作?

脚本

假设你有一个C#WinForms应用程序进行一些数据处理。 您有一个方法可以从UI线程调用的数据库中检索数据。 然后运行后台线程来执行此任务。 您希望UI继续执行其操作而不会被锁定和无响应。

如何让后台线程运行并进行处理,然后在返回结果时自动提醒UI线程?

如果不使用后台工作线程(无论出于何种原因),则必须从线程中触发由UI线程处理的事件。 例如,我有这个代码可以扫描我的mp3,并为每个找到的专辑发送火灾和事件,然后在完成(或停止)时扫描另一个事件:

public void Build() { FindAlbums(Root); // Final update if (Library_Finished != null) { Library_Finished(this, null); } } private void FindAlbums(string root) { // Find all the albums string[] folders = Directory.GetDirectories(root); foreach (string folder in folders) { string[] files = Directory.GetFiles(folder, "*.mp3"); if (files.Length > 0) { // Add to library - use first file as being representative of the whole album var info = new AlbumInfo(files[0]); if (Library_AlbumAdded != null) { Library_AlbumAdded(this, new AlbumInfoEventArgs(info)); } } FindAlbums(folder); } } 

然后在UI线程(这是WinForms代码):

  private void Library_AlbumAdded(object sender, AlbumInfoEventArgs e) { if (dataGridView.InvokeRequired) { dataGridView.Invoke((MethodInvoker)delegate { AddToGrid(e.AlbumInfo); }); } else { AddToGrid(e.AlbumInfo); } } private void Library_Finished(object sender, EventArgs e) { if (dataGridView.InvokeRequired) { dataGridView.Invoke((MethodInvoker)delegate { FinalUpdate(); }); } else { FinalUpdate(); } } 

但是,我会建议您调查后台工作线程,因为它会为您完成大量的内务处理。 但是, RunWorkerCompleted事件中需要相同的处理代码才能更新UI。

有几种方法可以做到这一点,但最简单的方法是使用BackgroundWorker。

基本上它有两个代表,DoWork和WorkCompleted。 DoWork在单独的线程上执行,WorkCompleted回调在UI线程上发生。

以下是更多信息: http : //msdn.microsoft.com/en-us/library/system.componentmodel.backgroundworker.aspx

您可以使用BackgroundWorker在其DoWork事件处理程序中执行时间密集型处理。 然后处理RunWorkerComplete事件 – 它将在DoWork方法完成时触发。 虽然这一切都在进行,但您的UI线程将会愉快地运行。

如果您使用的是.NET 2.0或更高版本,那么使用BackgroundWorker线程可以更轻松地实现这一点。 它有自己的RunWorkerCompleted事件, 可以满足您的需求。

我强烈推荐BackgroundWorker。 它具有大多数开发人员在创建线程时所具有的function。 它们也更容易取消优雅,甚至可以报告进度。

尝试使用BackgrounWorker并向其RunWorkerCompleted事件注册处理程序。

在Winforms中,您可以使用.Invoke方法(并检查.InvokeRequired属性)来将回调编组回UI线程。 您没有那么多通知UI线程 – 它继续进行并且不等待任何类型的完成,但您可以使用另一个线程与控件(例如,更新标签的text属性)进行交互Invoke方法。

您还可以使用BackgroundWorker对象(阅读MSDN以了解有关它的更多信息),该对象实现了在后台工作完成后在UI线程上运行某些代码的回调function。

如果您正在讨论WinForm应用程序,则可以使用表单上的Invoke方法(或表单上的任何控件)对任何UI对象进行更改。 您还可以找到有用的InvokeRequired属性

您可以使用Dispatcher.CurrentDispatcher存储对UI线程Dispatcher的引用(显然在GUI线程调用的方法中)。 使用此对象,您可以在工作线程中使用BeginInvoke或Invoke方法在GUI线程上执行一个方法,通知它您已完成工作。 我个人认为这种方法比使用后台工作者对象稍微灵活一些,并且可以产生稍微更易读的代码。

在C#中使用多个线程有一种简单的方法。 它被称为BackgroundWorker。 你应该看看它: BackgroundWorker教程

如前所述,可以使用BackgroundWorker类。

或者,您可以执行类似于以下操作的操作:

 void buttonGo_Clicked( object sender, EventArgs e ) { MyAsyncClass class = new MyAsyncClass(); class.LongOperationFinished += (LongOperationFinishedEventHandler)finished; class.BeginLongOperation(); } void finished( object sender, EventArgs e ) { if( this.InvokeRequired ) { this.BeginInvoke( (LongOperationFinishedEventHandler)finished, sender, e ); return; } // You can safely modify the gui here. }