從根本上說,這個問題是不是真正的遞歸或支持多線程,它很簡單:
如何在一個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