2014-06-26 15 views
1

我試圖執行一個命令行程序,並打印其輸出到實時文本框:文本框沒有得到來自不同的線程更新,除非顯示的MessageBox

private void btnExecute_Click(object sender, EventArgs e) 
{ 
    ProcessStartInfo startInfo = new ProcessStartInfo(); 
    startInfo.WindowStyle = ProcessWindowStyle.Hidden; 
    startInfo.CreateNoWindow = true; 
    startInfo.FileName = Application.StartupPath + "\\Deps\\ats.exe"; 
    startInfo.UseShellExecute = false; 
    startInfo.RedirectStandardOutput = true; 

    using (Process exeProcess = Process.Start(startInfo)) 
    { 
     exeProcess.OutputDataReceived += exeProcess_OutputDataReceived; 
     exeProcess.BeginOutputReadLine(); 

     //MessageBox.Show("Hello"); //Notice this message box before calling WaitForExit      
     exeProcess.WaitForExit(45000); 
    } 

    private void exeProcess_OutputDataReceived(object sender, DataReceivedEventArgs e) 
    { 
     if (txtOutput.InvokeRequired) 
     { 
      txtOutput.Invoke(new MethodInvoker(delegate { txtOutput.Text += Environment.NewLine + e.Data; })); 
     } 
    } 
} 

的代碼運行沒有錯誤,但不打印任何東西到txtOutput 然而,如果我取消註釋消息框,消息框顯示和txtOutput實時更新 現在如果我點擊'確定'關閉消息框,txtOutput停止更新再次!

這裏究竟發生了什麼?爲什麼只有當我顯示MessageBox時才更新textBox?

+0

我懷疑你是不是真正從控制檯應用程序的方式,你得到的輸出認爲你是(我的控制檯重定向有點生疏)。在代理中放置一些調試代碼,將'e.Data'輸出到調試窗口,以驗證你實際上是否獲得了一些輸出。 – CodingGorilla

+0

@CodingGorilla,我知道我從控制檯應用程序的輸出,因爲只要MessageBox顯示文本框顯示輸出,但只要我關閉消息框輸出停止更新 – user3006467

回答

0

好的,所以你在這裏的問題可能是exeProcess.WaitForExit(45000);阻塞了UI線程。所以對txtOutput.Invoke的調用將消息發送到由UI線程處理的窗口消息隊列。由於該UI線程被等待狀態阻塞,因此無法處理這些文本框文章。

所以你需要做的是等待進程退出而不會阻塞UI線程。有幾種方法可以做到這一點,但一種方法是使用回撥過程Exited事件。我沒有看夠你的代碼在這裏給一個完整的例子,但你要重寫是這樣的:

private Process _exeProcess; 

private void btnExecute_Click(object sender, EventArgs e) 
{ 
    ProcessStartInfo startInfo = new ProcessStartInfo(); 
    startInfo.WindowStyle = ProcessWindowStyle.Hidden; 
    startInfo.CreateNoWindow = true; 
    startInfo.FileName = Application.StartupPath + "\\Deps\\ats.exe"; 
    startInfo.UseShellExecute = false; 
    startInfo.RedirectStandardOutput = true; 

    _exeProcess = Process.Start(startInfo); 
    _exeProcess.OutputDataReceived += exeProcess_OutputDataReceived; 
    _exeProcess.BeginOutputReadLine();  
    _exeProcess.Exited += ContinueOnYourWay; 
} 

private void ContinueOnYourWay(object sender, EventArgs e) 
{ 
    // Clean up 
    _exeProcess.Dispose(); 
    _exeProcess = null; 

    // More code here 
} 

private void exeProcess_OutputDataReceived(object sender, DataReceivedEventArgs e) 
{ 
    if (txtOutput.InvokeRequired) 
    { 
     txtOutput.Invoke(new MethodInvoker(delegate { txtOutput.Text += Environment.NewLine + e.Data; })); 
    } 
} 
+0

是的,這將工作,我會稍微修改我的代碼的其餘部分,我想我也可以等等:while(!exeProcess.HasExited) { //Thread.Sleep(500); Application.DoEvents(); } – user3006467

+0

正如一般的經驗法則,在UI事件處理程序(即UI線程)中放置任何類型的等待通常是一個糟糕的主意。這幾乎總是會導致您的用戶界面凍結並變得無法響應,並且在更高版本的Windows中會導致「該程序沒有響應」對話框詢問用戶是否想要殺死它。 – CodingGorilla

+0

剛纔看到了對之前評論的修改。 'Application.DoEvents()'工作,它基本上產生到'WndProc'來允許它處理一些事件。我個人不會這樣做,但它應該工作。 – CodingGorilla

相關問題