除非显示MessageBox,否则TextBox不会从不同的线程更新

时间:2014-06-26 23:42:05

标签: c# multithreading user-interface

我正在尝试执行命令行程序并将其输出实时打印到文本框中:

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打印任何内容 但是,如果我取消注释消息框,则会显示MessageBox并实时更新txtOutput 现在,如果我点击“确定”'关闭MessageBox,txtOutput再次停止更新!!

这到底发生了什么?为什么textBox只在我显示MessageBox时更新?

1 个答案:

答案 0 :(得分: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; }));
    }
 }