更好的将标准输出输出到 WPF UI 的方法

huangapple go评论129阅读模式
英文:

Better way to output stdout to WPF UI

问题

以下是您要翻译的代码部分:

I need to run and watch some slow bat-files in our system from a WPF/C# user interface.
The user interface should not wait for the process to end but display it whenever something happens in the bat file.

The following code works for now but introduced a thread to handle it.
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);
        });
    }
}
A few notes:
```lvConsoleOutput``` is a regular listview that is associated with ```m_ConsoleRows``` which is an ObservableCollection<string>.
The contents of a sample run.bat file here:
echo 1
echo 2
timeout 2
echo more text 3
timeout 1
echo almost the end
timeout 3
echo DONE!
By not running this in a thread, the entire UI freezes until the entire bat file has run until completion. Then I get the output in the UI and it unfreezes again.
With ```thread1``` above I get the achieved result but...

My questions are:

Can I do this without introducing a thread?

Are there cleaner ways to achieve this?
英文:

I need to run and watch some slow bat-files in our system from a WPF/C# user interface.
The user interface should not wait for the process to end but display it whenever something happens in the bat file.

The following code works for now but introduced a thread to handle it.

        private void OnClick(object sender, RoutedEventArgs e)
        {
            Thread thread1 = new Thread(() =&gt;
            {
                System.Diagnostics.Process p = new System.Diagnostics.Process();
                p.StartInfo.WorkingDirectory = &quot;C:\my\folder\with\batfile&quot;;
                p.StartInfo.FileName = &quot;cmd.exe&quot;;
                p.StartInfo.Arguments = &quot;/C run.bat&quot;;
                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(() =&gt;
                {
                    m_ConsoleRows.Add(e.Data);
                });
            }
        }

A few notes:
lvConsoleOutput is a regular listview that is associated with m_ConsoleRows which is an ObservableCollection<string>.

The contents of a sample run.bat file here:

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

By not running this in a thread, the entire UI freezes until the entire bat file has run until completion. Then I get the output in the UI and it unfreezes again.
With thread1 above I get the achieved result but...

My questions are:

Can I do this without introducing a thread?

Are there cleaner ways to achieve this?

答案1

得分: 1

不在线程中运行此操作会导致整个用户界面冻结,直到整个批处理文件运行完成。

这是因为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();
}

顺便提一下,由于您已经直接访问了ListBox,所以不一定需要ObservableCollection作为其ItemsSource。以下代码同样有效,而且代码更少:

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

> By not running this in a thread, the entire UI freezes until the entire bat file has run until completion.

That is because of the WaitForExit call. Just remove it:

private void OnClick(object sender, RoutedEventArgs e)
{
    System.Diagnostics.Process p = new System.Diagnostics.Process();
    p.StartInfo.WorkingDirectory = @&quot;C:\my\folder\with\batfile&quot;;
    p.StartInfo.FileName = &quot;cmd.exe&quot;;
    p.StartInfo.Arguments = &quot;/C run.bat&quot;;
    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();
}

As a note, since you are directly accessing the ListBox anyway, you do not strictly need the ObservableCollection as its ItemsSource. This works as well with less code:

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

huangapple
  • 本文由 发表于 2023年3月7日 23:01:15
  • 转载请务必保留本文链接:https://go.coder-hub.com/75663651.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定