Do Jobs really work in background in powershell? -
i trying implement background commands initiate after user clicks button, , far have ended ui locking while job on-going. using time consuming loop check if ui locks up. can let job work in background ui freed up. not sure want complicate code adding runspaces. doing incorrectly?
$inputxml = @" <window x:class="wpfapplication2.mainwindow" xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:local="clr-namespace:wpfapplication2" mc:ignorable="d" title="create user" height="448.05" width="656.017" resizemode="noresize"> <grid margin="0,0,-6.8,-0.8" background="#ffd7d7d7"> <grid.rowdefinitions> <rowdefinition height="403*"/> <rowdefinition height="18*"/> </grid.rowdefinitions> <grid.columndefinitions> <columndefinition/> </grid.columndefinitions> <button x:name="create_user" content="create user" horizontalalignment="left" margin="67,224,0,0" verticalalignment="top" width="300" height="26" rendertransformorigin="0.551,-0.671" isenabled="true"> <button.background> <lineargradientbrush endpoint="0,1" startpoint="0,0"> <gradientstop color="#fff3f3f3" offset="0"/> <gradientstop color="#ffebebeb" offset="0.5"/> <gradientstop color="#ffdddddd" offset="0.5"/> <gradientstop color="#ffcdcdcd" offset="1"/> </lineargradientbrush> </button.background> </button> <label x:name="fname" content="" horizontalalignment="left" margin="43,11,0,0" verticalalignment="top" height="26" width="10"/> <label x:name="fname1" content="first name" horizontalalignment="left" margin="88,54,0,0" verticalalignment="top" width="72" rendertransformorigin="0.513,1.469" height="26"/> <label x:name="lname" content="last name" horizontalalignment="left" margin="88,83,0,0" verticalalignment="top" rendertransformorigin="-0.167,-0.458" width="72" height="25"/> <textbox x:name="fnametxt" height="23" margin="167,54,0,0" textwrapping="wrap" verticalalignment="top" rendertransformorigin="0.501,0.452" horizontalalignment="left" width="136"/> <button x:name="exitbtn" content="exit" horizontalalignment="left" verticalalignment="top" width="135" margin="447,365,0,0" height="38" rendertransformorigin="0.489,0.462"/> <label x:name="label" content="password" horizontalalignment="left" margin="92,113,0,0" verticalalignment="top" rendertransformorigin="0.064,0.601" height="26" width="68"/> <passwordbox x:name="passwordbox" margin="167,113,0,0" verticalalignment="top" height="24" horizontalalignment="left" width="136"/> <textbox x:name="stsbox" horizontalalignment="left" height="62" margin="67,267,0,0" textwrapping="wrap" verticalalignment="top" width="300" background="#ffdadada" foreground="black" opacity="0.45" selectionbrush="#ff1d6ebf" rendertransformorigin="0.503,-0.59" isreadonly="true"/> <textbox x:name="lnametxt" height="23" margin="167,85,0,0" textwrapping="wrap" verticalalignment="top" horizontalalignment="left" width="136"/> </grid> </window> "@ $inputxml = $inputxml -replace 'mc:ignorable="d"','' -replace "x:n",'n' -replace '^<win.*', '<window' [void][system.reflection.assembly]::loadwithpartialname('presentationframework') [void][system.reflection.assembly]::loadwithpartialname("system.windows.forms") [xml]$xaml = $inputxml #read xaml $reader=(new-object system.xml.xmlnodereader $xaml) try{$form=[windows.markup.xamlreader]::load( $reader )} catch{write-host "unable load windows.markup.xamlreader. double-check syntax , ensure .net installed."} $xaml.selectnodes("//*[@name]") | %{set-variable -name "wpf$($_.name)" -value $form.findname($_.name) -scope global} function global:get-formvariables{ if ($global:readmedisplay -ne $true) {$global:readmedisplay=$true} #write-host "found following interactable elements our form" -foregroundcolor cyan get-variable wpf* } get-formvariables $wpfcreate_user.add_click({ $test = { for($i=1; $i -le 100000; $i++){ $z = $i + $z $z }} $job = start-job $test wait-job $job receive-job $job -outvariable results remove-job $job $wpfstsbox.text = "$results`n" }) $wpfexitbtn.add_click({ $form.close() | out-null exit}) $form.showdialog() | out-null
yes, psjobs "background" jobs.
when call start-job, separate process started, executing job/command.
in script, job doesn't block calling thread, subsequent command (wait-job $job) does.
if fire off start-job , return click handler, ui wouldn't lock up:
$button.add_click({ $jobcode = { start-sleep -seconds 10 } $job = start-job $jobcode }) you'll see ui becomes responsive again in way lees 10 seconds.
the problem no longer have access $job , no longer control on when displayed.
to compensate this, need background thread or timed event can periodically check on job(s) , output result.
you use timer , powershell's builtin eventing infrastructure this:
# create timer $backgroundtimer = new-object system.timers.timer # set interval (ms) $backgroundtimer.interval = 500 # make sure timer stops raising events after each interval $backgroundtimer.autoreset = $false # have powershell "listen" event in background register-objectevent $backgroundtimer -eventname 'elapsed' -sourceidentifier 'timerelapsed' -action { # loop through completed jobs data return, "oldest" "newest" while(($finishedjob = get-job |where-object {$_.state -eq 'completed' -and $_.hasmoredata}|select-object -first 1)) { # update text box on wpf form results # note: event executed in separate scope, "global:" scope prefix $global:wpfstsbox.text = "$(receive-job $finishedjob)`n" # clean job remove-job $finishedjob } # restart timer $backgroundtimer.start() } # enable timer $backgroundtimer.enabled = $true
Comments
Post a Comment