2015-08-27 90 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

相关问题