2016-06-21 67 views
1

我有一個簡單的控制檯應用程序,可以向標準輸出報告進度。例如:如何根據進程的控制檯輸出更新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(進度條,具體地)異步:

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屬性。

+0

如果你聲明類似於'public System.Windows.Threading。Dispatcher dispatch = System.Windows.Threading.Dispatcher.CurrentDispatcher;'當應用程序初始化並使用該調度程序時,它是否會改變行爲? – pay

+0

@pay:無論我在'MainWindow'還是'App'中放置'dispatch'都沒有改變。 –

+0

嗯,所以即使調度器是在UI線程上創建的,它仍然會死鎖?也許可以從該事件處理程序的內部刪除。 – pay

回答

-1

建議將您的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"/> 
+0

你可以顯示代碼如何工作這個案例? –

+0

這是非常微不足道的,我相信你可以做到這一點。 –

+0

@CraigW:真的嗎? –

1

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確保線程的調度員,你的進度存在叫做。 請注意,我沒有運行此代碼,它是從我使用的改編而來。

請原諒任何錯誤,首先發布。 此外,我很抱歉重振這樣一箇舊帖子,但這是谷歌的結果,我希望我可以幫助某人。