2015-08-27 115 views
0

我有一個WPF應用程序來運行測試用例並收集結果。在主窗口上,使用可以選擇一些測試用例並循環運行。當運行一個案例時,一個自定義的子窗口將彈出並顯示用戶一些數據,然後用戶單擊按鈕「通過」或「失敗」來設置此測試用例的結果並關閉此子窗口。然後下一個測試用例開始運行。在主窗口中,有一個「Stop」按鈕。用戶可以通過點擊它來停止當前回合完成後的迴路測試。 代碼如下:在WPF(.net 4.0)中,如何在不阻塞主窗口的情況下讓子窗口阻塞代碼?

while (!stopByUser) 
{ 
    foreach(var caseItem in caseList) 
    { 
     // on TestWindow UI, caseItem.isPassed will be set by user with clicking buttons; 
     caseItem.isPassed = false; 
     TestWindow tw = new TestWindow(caseItem); 
     tw.ShowDialog(); 
     if (caseItem.isPassed) 
     { 
     totalPassed++; 
     // update UI ... 
     } 
    } 
} 

的問題是用戶不能點擊主窗口上的「停止」按鈕,因爲我用tw.ShowDialog()彈出一個模式窗口。不過,我也不能簡單地將它改爲tw.Show()來彈出一個非模態窗口,因爲foreach循環中的代碼必須同步執行。

而我發現本機MessageBox有這種能力:阻止代碼,而不阻止主窗口。例如。

var result= MessageBox.Show(message, "Is this test case passed?", MessageBoxButton.YesNo); 
// the following line will be executed after the MessageBox is closed 
// and meanwhile I can operate my main window when the MessageBox is still visible 
var passed = (judgement == MessageBoxResult.Yes); 

所以我的問題是我怎麼能實現在.NET 4.0中使用WPF窗口這個能力嗎? 我的應用程序將在Windows XP上運行,所以.NET 4.0是強制性的。

任何想法?提前致謝!

+0

您的設計需求可能有問題,但如果您想堅持下去,您仍然有一些選擇:1)爲消息框使用單獨的UI線程,2)使用p/invoke並調用原生'MessageBox' API,3)使用'Microsoft.Bcl.Async'和'async/await'讓你保持'foreach'循環,同時仍然使用@VMaleev建議的無模式'Window.Show/Close'。 – Noseratio

回答

0

MessageBox.Show阻止所有窗口,因爲它使用ShowDialog方法。你可以做的就是寫邏輯:

  1. 給下一個項目
  2. 創建新的窗口,它
  3. 訂閱此窗口的關閉事件
  4. OnClosed事件更新UI並轉到步驟一個

實施例:

private bool stopByUser {get;set;} 
    private int currentItemIndex {get;set;} 
    private List<object> caseList {get;set;}] 
    private TestWindow tw {get;set; 
    public void OnLoaded(object sender, RoutedEventArgs e) 
    { 
     ShowNext(); 
    } 

    private void ShowNext() 
    { 
     if (stopByUser) return; 

     var caseItem = caseList[currentItemIndex++] 
     caseItem.isPassed = false; 

     tw = new TestWindow(caseItem); 
     tw.Closed += (s, e) => 
     { 
      if (caseItem.isPassed) 
      { 
       totalPassed++; 
       // update UI ... 

       ShowNext(); 
      } 
     }; 
     tw.Show(); 
    } 
+0

MessageBox.Show()似乎不會阻止主窗口。我仍然可以與主窗口進行交互。例如。點擊「停止」按鈕 – ricky

+0

我不行。你可以在這個行爲所在的地方共享示例項目。同時,我建議你的問題真正的解決方法。 – VMaleev

0

感謝@Noseratio和@ VMaleev的幫助,我最終通過使用Microsoft.Bcl.Async和async/await得到了一個解決方案。這不是美麗的,但它的作品。

while (!stopByUser) 
{ 
    foreach(var caseItem in caseList) 
    { 
     caseItem.isPassed = false; 
     GlobalVar.isFinished = false; // static variable: isFinished 
     TestWindow tw = new TestWindow(caseItem); 
     tw.Closed += (s, e) => 
     { 
      GlobalVar.isFinished = true; 
     }; 
     Task task = new Task(() => 
     { 
      while (!GlobalVar.isFinished) 
      { 
       Thread.Sleep(100); 
      } 
     }); 
     task.Start(); 
     tw.Show(); 
     await task; 
     // get the test result here from GlobalVar.isPassed 
     var passed = caseItem.isPassed; 
     // do other things 
    } 
} 

請記住,使用Microsoft.Bcl.Async,.NET框架4.0(含KB2468871)必須安裝在XP/WIN7。查看更多here

+0

你應該在這裏使用'TaskCompletionSource'而不是'Task'。 – Noseratio

相關問題