从根本上说,这个问题实际上与递归或多线程无关,只是这样:
如何在 GUI 应用程序的后台执行长时间运行的操作以使应用程序保持响应?
实现您自己的线程模型不是的方法,尤其是当您刚刚开始学习多线程/异步操作时。 .NET Framework 已经具有一个组件来满足您的需求:BackgroundWorker,它适用于 Winforms 和 WPF(以及几乎任何其他架构)。 p>
使用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 事件,并确保在BackgroundWorker 上将WorkerSupportsCancellation 设置为true。之后,您运行该操作:
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。