I would like to modernize the look of my app by switching to WPF. I need to recreate "Display output of the CMD in real-time inside TextBox" viewtopic.php?t=12969 but for WPF.
The problem is that WPF threading is completely different and it doesn't have "process.SynchronizingObject/System.ComponentModel.ISynchronizeInvoke" so Dispatcher must be used somehow.
After many strougles, I was able to comeup with this:
Code: Select all
Add-Type -AssemblyName PresentationFramework
$Xaml = New-Object System.Xml.XmlNodeReader([XML]@"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
Title="Test" WindowStartupLocation = "CenterScreen" ShowInTaskbar = "True">
<Grid>
<TextBox x:Name = "TextBox"/>
</Grid>
</Window>
"@)
Function Start-Worker {
$TextBox = $Window.FindName("TextBox")
$SyncHash = [hashtable]::Synchronized(@{Window = $Window; TextBox = $TextBox})
$Runspace = [runspacefactory]::CreateRunspace()
$Runspace.ThreadOptions = "ReuseThread"
$Runspace.Open()
$Runspace.SessionStateProxy.SetVariable("SyncHash", $SyncHash)
# Problem 1 - UI is lagging
$Worker = [PowerShell]::Create().AddScript({
for($Progress=1; $Progress -le 25; $Progress++){
$SyncHash.Window.Dispatcher.Invoke([action]{$SyncHash.TextBox.AppendText($Progress)}) | Out-Null
}
})
$Worker.Runspace = $Runspace
$Worker.BeginInvoke()
# Problem 2, even empty OutputDataReceived will cause crash
# $Worker = [PowerShell]::Create().AddScript({
# $process = New-Object System.Diagnostics.Process
# $process.StartInfo.FileName = 'ping.exe'
# $process.StartInfo.Arguments = 'google.com -n 3'
# $process.StartInfo.UseShellExecute = $false
# $process.StartInfo.CreateNoWindow = $true
# $process.StartInfo.RedirectStandardInput = $false
# $process.StartInfo.RedirectStandardOutput = $true
# $process.EnableRaisingEvents = $true
# $process.add_OutputDataReceived({
# # even empty OutputDataReceived will cause crash
# #[System.Console]::WriteLine( $_.Data)
# #$SyncHash.Window.Dispatcher.Invoke([action]{$SyncHash.TextBox.AppendText($_.Data)})
# })
# $process.Start() | Out-Null
# $process.BeginOutputReadLine()
# })
# $Worker.Runspace = $Runspace
# $Worker.BeginInvoke()
}
$script:Window = [Windows.Markup.XamlReader]::Load($Xaml)
$script:TextBox = $Window.FindName("TextBox")
$Window.Add_Loaded({ Start-Worker })
[Void]$Window.ShowDialog()
1. UI is lagging
2. Adding OutputDataReceived (even empty) cause crash - no process output can be received
I don't know how to improve solution further. Can someone please take look?