如何根据进程的控制台输出更新WPF控件?

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了如何根据进程的控制台输出更新WPF控件?相关的知识,希望对你有一定的参考价值。

我有一个简单的控制台应用程序,报告标准输出的进度。例如:

static void Main(string[] args)
{
    for (int i = 0; i <= 100; i += 10)
    {
        Console.WriteLine(i);
        System.Threading.Thread.Sleep(1000);
    }
}

产生这个输出:

0
10
20
30
40
50
60
70
80
90
100

我想通过.NET Process调用此应用程序,并异步更新WPF控件(ProgressBar):

private void Run()
{
    Process process = new Process();
    process.StartInfo.FileName = "ConsoleApplication1.exe";
    process.StartInfo.UseShellExecute = false;
    process.StartInfo.CreateNoWindow = true;
    process.StartInfo.RedirectStandardOutput = true;
    process.OutputDataReceived += new DataReceivedEventHandler((sender, e) =>
    {
        if (e.Data != null)
        {
            Console.WriteLine(e.Data);
            ProgressBar.Value = double.Parse(e.Data);
        }
    });
    process.Start();
    process.BeginOutputReadLine();
    process.WaitForExit();
    process.Close();
}

当我运行它时,它写入控制台没有问题,但可以理解的是抱怨尝试从不同的线程访问ProgressBar,所以我用一个调用包装它:

Application.Current.Dispatcher.Invoke(() =>
{
    ProgressBar.Value = double.Parse(e.Data);
});

但是,当它命中调用时会冻结。据推测,虽然我不明白为什么会出现僵局。

环顾四周,似乎Process.SynchronizingObject旨在解决这些问题,但我无法看到如何从WPF中使用它,因为控件没有ISynchronizeInvoke属性。

答案

WaitForExit()使当前线程等待,直到关联的进程终止。应该在进程上调用所有其他方法之后调用它。要避免阻止当前线程,请使用Exited事件。

资料来源:MSDN

因此,您不应该使用process.WaitForExit(),因为它会使UI线程等待进程退出。如果只想在进程退出后执行代码,请处理process.Exited事件。

此外,process.ErrorDataReceivedprocess.OutputDataReceivedprocess.Exited在另一个线程中被提出。为了让它们与UI线程中的控件(即你的ProgressBar)进行交互,你应该以这种方式处理事件:

private void process_OutputDataReceived(object sender, DataReceivedEventArgs e)
    {
        // do additional processing with e.Data if this is what you desire
        ProgressBar.Dispatcher.Invoke(new Action(()=> { ProgressBar.Value=double.Parse(e.Data); }));
    }

使用ProgressBar.Dispatcher可确保调用ProgressBar存在的线程的调度程序。请注意,我没有运行此代码,它改编自我使用的。

请原谅任何错误,首先发布。此外,我很抱歉恢复这么老的帖子,但这是谷歌的结果,我希望我可以帮助别人。

另一答案

建议将ProgressBar绑定到触发change notifications并更新该对象属性的对象。这样你就可以避免直接使用Dispatcher并访问视图(你可能不应该这样)。

private double _Progress = 0;
public double Progress
{
    get { return _Progress; }
    set
    {
        if (value != _Progress)
        {
            _Progress = value;
            OnPropertyChanged("Progress");
        }
    }
}

// Dummy updates, 10% every second
new Thread(p =>
{
    for (int i = 0; i < 10; i++)
    {
        Progress += 10;
        Thread.Sleep(1000);
    }
}).Start();
<ProgressBar Value="{Binding Progress}" Height="20px" HorizontalAlignment="Stretch"/>

以上是关于如何根据进程的控制台输出更新WPF控件?的主要内容,如果未能解决你的问题,请参考以下文章

wpf怎么动态 控制控件位置c#代码

WPF如何把隐藏控件显示出来

wpf中我自定义了一个自定义控件,add到了界面,如何设置显示在最底层?后台代码如何控制?

求C#代码,控制WPF控件颜色变化

立即从进程回调输出更新列表视图 C# WPF

创建在外部进程中运行的 WPF“控件”