2013-12-20 61 views
0

我編寫了模擬尋路算法的應用程序。我可以運行算法或步驟(如調試)。但是當我運行算法時,我無法在算法完成之前進行任何修改。如何在循環內允許消息

private void menu_run_Click(object sender, EventArgs e) 
{ 
    algorithm.Reset(); 
    while (algorithm.status == Algorithm.Status.Searching) 
    { 
     algorithm.MakeStep(); 
     if (this.speed != 0) System.Threading.Thread.Sleep(this.speed); 

     drawing_area.Invalidate(); 
    } 
} 

我想這是因爲我在一個週期內完成所有操作,系統無法處理我觸發的新消息(事件)。

那麼我應該如何更改我的代碼以便能夠在每次迭代後重新繪製更改?

  1. 我應該不知何故調用Message Dispatcher讓他在每次迭代後處理新消息嗎?
  2. 我應該創建自己的消息並使用消息完成周期內的所有工作嗎?
  3. 還是有更優雅的方式嗎?
+0

作爲一個快速的回答,'Application.DoEvents'運行消息隊列處理,所以它可能是你想要的。在「Invalidate」後調用它,它應該處理重繪繪製區域。儘管如此,Timer組件可能會更有用。 – Luaan

回答

1

有很多不同的方法來做到這一點。

對於您的情況,最簡單的方法是在窗體上使用System.Windows.Forms.Timer對象,而不是以無限循環調用Sleep()

  1. 將計時器從工具箱添加到表單中。
  2. 將其Interval財產設置爲this.speed
  3. 將其Enabled屬性設置爲true
  4. 訂閱計時器的Tick事件。

處理程序會是這個樣子:

private void OnTimerTick(object sender, EventArgs e) 
{ 
    if (algorithm.Status == Algorithm.Status.Searching) 
    { 
     algorithm.MakeStep(); 
     drawing_area.Invalidate(); 
    } 
} 

你可能只需要略微修改你的控制邏輯(其中算法開始和停止)。如果有幫助,你可以使用定時器的Enabled屬性。

另一種解決方案是創建一個背景線程的對象,在算法運行時引發週期性事件,表單將訂閱這些事件並相應地重繪(不要忘記在事件中使用Invoke,將來自非GUI線程)。

還有BackgroundWorker你可以把它看作是第三種選擇。但我認爲計時器對你來說最簡單。