如何根据进程的控制台输出更新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.ErrorDataReceived
,process.OutputDataReceived
和process.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控件?的主要内容,如果未能解决你的问题,请参考以下文章