从根本上说,这个问题是不是真正的递归或支持多线程,它很简单:
如何在一个GUI应用程序的后台执行一个长期运行的操作,这样该应用住宿响应?
实现自己的线程模型是不去这里的路,特别是如果你是刚开始学习多线程/异步操作。 .NET框架已经有你想要做的一个组件:BackgroundWorker,它可以在Winforms和WPF(以及几乎任何其他体系结构)中工作。
使用BackgroundWorker
来完成您想要的任务非常非常容易。我将假设Winforms为这个例子,但是这是just as easy in WPF。
// Don't actually write this line; it will be in the .designer.cs file when you
// drop a BackgroundWorker onto the form/control. This is for reference only.
private BackgroundWorker bwRecursive;
private void bwRecursive_DoWork(object sender, DoWorkEventArgs e)
{
MyTreeNode root = (MyTreeNode)e.Argument;
ExecuteRecursiveOperation(root);
}
private void bwRecursive_RunWorkerCompleted(object sender,
RunWorkerCompletedEventArgs e)
{
// Optionally update the GUI with the results here
}
private void ExecuteRecursiveOperation(MyTreeNode node)
{
if (bwRecursive.CancellationPending)
return;
foreach (MyTreeNode childNode in node.ChildNodes)
{
if (bwRecursive.CancellationPending)
break;
ExecuteRecursiveOperation(childNode);
}
}
显然,你也必须要连接的DoWork
和RunWorkerCompleted
事件,并确保设置WorkerSupportsCancellation
到true
在BackgroundWorker
。在此之后,运行与操作:
bwRecursive.RunWorkerAsync(someTreeNode);
并与取消:
bwRecursive.CancelAsync();
这里唯一的皱纹是,你说你希望每个之后暂停(不停止)执行“步”。我可能会使用AutoResetEvent
来做到这一点,这是一种事件类型,每次等待成功时都会重置其信号(“就绪”)状态。再次,这是只有几行代码整合:
public class MyForm : Form
{
private AutoResetEvent continueEvent = new AutoResetEvent(false);
// Previous BackgroundWorker code would go here
private void ExecuteRecursiveOperation(MyTreeNode node)
{
if (bwRecursive.CancellationPending)
return;
foreach (MyTreeNode childNode in node.ChildNodes)
{
continueEvent.WaitOne(); // <--- This is the new code
if (bwRecursive.CancellationPending)
break;
ExecuteRecursiveOperation(childNode);
}
}
private void btnContinue_Click(object sender, EventArgs e)
{
continueEvent.Set();
}
private void btnCancel_Click(object sender, EventArgs e)
{
bwRecursive.CancelAsync();
continueEvent.Set();
}
private void btnStart_Click(object sender, EventArgs e)
{
continueEvent.Set();
bwRecursive.RunWorkerAsync(...);
}
}
有一件事可能在这里需要额外的解释,那就是取消方法,它先取消,然后设置continueEvent
。有必要这样做,因为如果工作人员仍在等待事件发生,实际上将不会取消到取消阶段,因此当您取消时,您需要允许该工作人员继续。如果您希望执行第一步而不要求用户点击“继续”,则您还需要设置continueEvent
当开始工作人员。“
如果你不想冻结UI线程,然后不要运行要冻结UI线程上的代码。 (医生,当我这样做的时候会感到痛苦 - 所以*不要这样做*)。运行它自己的线程并冻结它。 – 2010-03-27 15:04:10