I am trying to learn how to use a Runspace to pass values to a GUI. I have been tweaking the script written by Boe Prox, trying to understand how Dispatcher.Invoke works with a runspace and came across a very strange problem
$uiHash = [hashtable]::Synchronized(@{})
$newRunspace =[runspacefactory]::CreateRunspace()
$newRunspace.ApartmentState = "STA"
$newRunspace.ThreadOptions = "ReuseThread"
$newRunspace.Open()
$newRunspace.SessionStateProxy.SetVariable("uiHash",$uiHash)
$psCmd = [PowerShell]::Create().AddScript({
$uiHash.Error = $Error
[xml]$xaml = @"
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
x:Name="Window" Title="Initial Window" WindowStartupLocation = "CenterScreen"
Width = "650" Height = "800" ShowInTaskbar = "True">
<TextBox x:Name = "textbox" Height = "400" Width = "600"/>
</Window>
"@
$reader=(New-Object System.Xml.XmlNodeReader $xaml)
$uiHash.Window=[Windows.Markup.XamlReader]::Load( $reader )
$uiHash.TextBox = $uiHash.window.FindName("textbox")
$uiHash.Window.ShowDialog() | Out-Null
})
$psCmd.Runspace = $newRunspace
$handle = $psCmd.BeginInvoke()
#-----------------------------------------
#Using the Dispatcher to send data from another thread to UI thread
Update-Window -Title ("Services on {0}" -f $Env:Computername)
$uiHash.Window.Dispatcher.invoke("Normal",[action]{$uiHash.TextBox.AppendText('test')})
If I were to use the last line of the script without the Update-Window -Title ("Services on {0}" -f $Env:Computername) I get a you cannot call a method on a null-valued expression. InvokeMethodOnNull error and the text is not appended. However, if I add Update-Window -Title ("Services on {0}" -f $Env:Computername) right above the Dispatcher.invoke line, I still get the error, but the textbox contains the appended text.
What is the reason for this occurrence? I have tried so many ways to use the Dispatcher.Invoke to add content to textboxes but always end up with a cannot call a method method on null error without any success, but now adding some lines that reference the UI and calling the Dispatcher.Invoke seems to make it work.