将stdout输出到WPF UI的更好方法

hivapdat  于 2023-03-09  发布在  其他
关注(0)|答案(1)|浏览(121)

我需要从一个WPF/C #用户界面运行并查看我们系统中的一些慢的bat文件。用户界面不应该等待进程结束,而是在bat文件中发生任何事情时显示它。
下面的代码现在可以工作,但引入了一个线程来处理它。

private void OnClick(object sender, RoutedEventArgs e)
        {
            Thread thread1 = new Thread(() =>
            {
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.WorkingDirectory = "C:\my\folder\with\batfile";
                p.StartInfo.FileName = "cmd.exe";
                p.StartInfo.Arguments = "/C run.bat";
                p.StartInfo.UseShellExecute = false;
                p.StartInfo.CreateNoWindow = true;
                p.StartInfo.RedirectStandardOutput = true;
                p.StartInfo.RedirectStandardError = true;
                p.EnableRaisingEvents = true;

                p.OutputDataReceived += P_OutputDataReceived;
                p.Start();
                p.BeginOutputReadLine();
                p.WaitForExit(20000);
            }
            );
            thread1.Start();
        }
        private void P_OutputDataReceived(object sender, DataReceivedEventArgs e)
        {
            if (!string.IsNullOrEmpty(e.Data))
            {
                lvConsoleOutput.Dispatcher.Invoke(() =>
                {
                    m_ConsoleRows.Add(e.Data);
                });
            }
        }

注意:lvConsoleOutput是与m_ConsoleRows相关联的常规列表视图,m_ConsoleRows是可观察集合。
示例run.bat文件的内容如下:

echo 1
echo 2
timeout 2
echo more text 3
timeout 1
echo almost the end
timeout 3
echo DONE!

如果不在线程中运行,整个UI将冻结,直到整个bat文件运行完成。然后我在UI中得到输出,它再次解冻。使用上面的thread1,我得到了实现的结果,但是...
我的问题是:
我可以不引入线程来完成此操作吗?
是否有更清洁的方法来实现这一目标?

mlmc2os5

mlmc2os51#

如果不在线程中运行,整个UI将冻结,直到整个bat文件运行完成。
这是因为WaitForExit调用。删除它即可:

private void OnClick(object sender, RoutedEventArgs e)
{
    System.Diagnostics.Process p = new System.Diagnostics.Process();
    p.StartInfo.WorkingDirectory = @"C:\my\folder\with\batfile";
    p.StartInfo.FileName = "cmd.exe";
    p.StartInfo.Arguments = "/C run.bat";
    p.StartInfo.UseShellExecute = false;
    p.StartInfo.CreateNoWindow = true;
    p.StartInfo.RedirectStandardOutput = true;
    p.StartInfo.RedirectStandardError = true;
    p.EnableRaisingEvents = true;
    p.OutputDataReceived += P_OutputDataReceived;
    p.Start();
    p.BeginOutputReadLine();
}

需要注意的是,由于您直接访问列表框,因此您并不一定需要ObservableCollection作为其ItemsSource,这样做也可以使用较少的代码:

private void P_OutputDataReceived(object sender, DataReceivedEventArgs e)
{
    if (!string.IsNullOrEmpty(e.Data))
    {
        lvConsoleOutput.Dispatcher.Invoke(() => lvConsoleOutput.Items.Add(e.Data));
    }
}

相关问题