如何在不阻止UI的情况下等待线程完成

我希望我的程序在下面的行之后等待

frmProgressBarObj = PullMSI.ExtractByMSIName("products.txt", false); 

如上所述,方法是通过StartProcessWithProgress()方法在内部调用线程。 我希望在执行代码逻辑-2行之前完成该线程。 同时,它不应该停止由frmProgressBar.UpdateProgress()完成UI更新。 我该怎么做呢?

 namespace NS1 { public partial class frmMain : Form { private void button1_Click(object sender, EventArgs e) { frmProgressBar frmProgressBarObj = PullMSI.ExtractByMSIName("products.txt", false); //code logic - 2 MessageBox.Show("This is executing immediately. I want to wait until above thread is complete"); } } public partial class frmProgressBar : Form { public void UpdateProgress(String strTextToDisplayOnProgress) { progressBar1.BeginInvoke( new Action(() => { progressBar1.Value++; lblFileName.Text = strTextToDisplayOnProgress; if (progressBar1.Value == progressBar1.Maximum) { this.Hide(); } })); } public delegate void DelProgress(); public void StartProcessWithProgress(DelProgress delMethodCode, int maxCount) { InitializeProgress(maxCount); Thread backgroundThread = new Thread(new ThreadStart(delMethodCode)); backgroundThread.Start(); } } public static class PullMSI { public static frmProgressBar ExtractByMSIName(String strProductFilePath, bool reNameMSI) { frmProgressBar frmProgressBar = new frmProgressBar(); frmProgressBar.StartProcessWithProgress(() => { //StreamRader sr declaration and other code while (!sr.EndOfStream) { //logic here frmProgressBar.UpdateProgress("Copying sr.msiname"); } }, 2); return frmProgressBar; } } } 

我很惊讶你以前没有使用过任何这些,但我真的建议你阅读C#中的线程,因为了解复杂性和学习语言对于它来说是非常重要的。

以下是您可以实现目标的三种不同方式:

1.使用重置事件 (进一步阅读: https : //msdn.microsoft.com/en-us/library/system.threading.manualreseteventslim ( v=vs.110 ) .aspx )。 如果您的C#版本没有ManualResetEventSlim ,请将其替换为ManualResetEvent并使用WaitOne()更改Wait() WaitOne()

 class LockingWithResetEvents { private readonly ManualResetEvent _resetEvent = new ManualResetEvent(false); public void Test() { MethodUsingResetEvents(); } private void MethodUsingResetEvents() { ThreadPool.QueueUserWorkItem(_ => DoSomethingLong()); ThreadPool.QueueUserWorkItem(_ => ShowMessageBox()); } private void DoSomethingLong() { Console.WriteLine("Doing somthing."); Thread.Sleep(1000); _resetEvent.Set(); } private void ShowMessageBox() { _resetEvent.WaitOne(); Console.WriteLine("Hello world."); } } 

2)使用任务并行库(TPL)。 进一步阅读: https : //msdn.microsoft.com/en-us/library/dd460717(v = vs.110).aspx

 class LockingWithTPL { public void Test() { Task.Factory.StartNew(DoSomethingLong).ContinueWith(result => ShowMessageBox()); } private void DoSomethingLong() { Console.WriteLine("Doing somthing."); Thread.Sleep(1000); } private void ShowMessageBox() { Console.WriteLine("Hello world."); } } 

3)使用Async / Await。 进一步阅读: https //msdn.microsoft.com/en-us/library/hh191443.aspx

 class LockingWithAwait { public void Test() { DoSomething(); } private async void DoSomething() { await Task.Run(() => DoSomethingLong()); ShowMessageBox(); } private async void DoSomethingLong() { Console.WriteLine("Doing somthing."); Thread.Sleep(10000); } private void ShowMessageBox() { Console.WriteLine("Hello world."); } } 

另外要了解:Mutex( https://msdn.microsoft.com/en-us/library/system.threading.mutex ( v= vs.110).aspx),Semaphore( https://msdn.microsoft.com /en-us/library/system.threading.semaphore(v=vs.110).aspx),Lock(https://msdn.microsoft.com/en-us/library/c5kehkcz.aspx),SemaphoreSlim(https : //msdn.microsoft.com/en-us/library/system.threading.semaphoreslim(v=vs.110).aspx),Monitor(https://msdn.microsoft.com/en-us/library/system 。 threading.monitor(v = vs.110).aspx )和Interlocked( https://msdn.microsoft.com/en-us/library/system.threading.interlocked (v=vs.110).aspx )。

如果您使用的是.NET 4.0(使用VS2012)或更高版本,则可以使用Task Parallel Libraryasync-await轻松完成此操作:

 private async void button1_Click(object sender, EventArgs e) { frmProgressBar frmProgressBarObj = await Task.Run(() => PullMSI.ExtractByMSIName("products.txt", false)); MessageBox.Show(string.Format("Returned {0}", frmProgressBarObj.ToString()); } 

对于.NET 4,您需要添加Microsoft.Bcl.Async