我有一个显示一个程序UI
,允许用户挑选通过查询获得的虚拟机名称Xen
池主服务器,然后创建针对所选择的虚拟机快照。 我想在后台创建快照,所以我可以保持UI
响应和更新UI
与进步创建的每个快照。
本来,我连接到Xen
池主服务器,然后再执行Xen
创建快照cmdlet的每个选择VM一旦UI
线程。 因此, UI
变得反应迟钝。
接下来,我连接到Xen
池主服务器,然后做了一个start-job
( background job
)每一次VM创建虚拟机的快照。 这失败,因为Xen
在创建的会话UI
线程不能传递给background job
(会话变量的内容,使之成块,但Xen的Connect
块中cmdlet返回一个Could not find open sessions to any XenServers
错误)。
然后,我搬到连接到Xen
池主服务器到background job
。 这减缓操作,因为建立连接需要几秒钟,并正在为每台虚拟机做一次。 然而, UI
仍然敏感,我能够用作业完成数据更新UI
。
我怎样才能保持UI
响应,更新UI
与进步创建的每个快照,而不是被强迫连接到服务器的每一次快照?
更新
该解决方案确实允许作为后台作业运行将在UI线程得到更新,但它并没有保持UI响应。 见我下面Rohin响应。
解决的办法是整个循环移动到background job
,并使用Write-Progress
cmdlet来对报告进度UI
。 信用卡使用Write-Progress
在这种情况下cmdlet的去瑞安
这里是表示所有需要的块一个简单的演示
cls
## Job code
$ScriptBlockCode =
{
param($items)
$retObj = @{}
try
{
$error.clear()
for ($i = 0; $i -lt $items.Count; $i++)
{
#wait to simulate the time it takes to do work on item $i
start-sleep -Seconds (get-random -Minimum 2 -Maximum 6)
# Use Write-Progress to report the completion of each item for as long as the job runs (Can be used to updage the UI)
# Use the -Completed argument to suppress displaying the progress bar
Write-Progress -Id ($i+1) -Activity ("For UI Update: " + $items[$i] + " processing complete") -Status "Reporting" -PercentComplete ((($i+1)/$items.Count)*100) -Completed
#Use a hashtable to report the status of each job. To be used in the calling code after the job status is no longer Running
#simulate some items passing, some failing
if ((get-random -Minimum 0 -Maximum 2) -eq 0)
{
$itemRet = [PSCustomObject]@{status="FAIL";details="some error description"}
}
else
{
$itemRet = [PSCustomObject]@{status="PASS";details=""}
}
$retObj.Add($items[$i],$itemRet)
}
return $retObj
}
catch
{
$itemRet = [PSCustomObject]@{status="ERROR";details=$error}
$retObj.Add("FATAL",$itemRet)
return $retObj
}
}
cls
#clean up before starting
Get-Job -Name "UniqueJobName" -ErrorAction SilentlyContinue | Stop-Job
Get-Job -Name "UniqueJobName" -ErrorAction SilentlyContinue | Remove-Job
#simulate 5 pieces of work
$items = @("Item A", "Item B", "Item C", "Item D", "Item E")
$job = Start-Job -Name "UniqueJobName" -ScriptBlock $ScriptBlockCode -ArgumentList ($items)
#loop and update UI until job is done
$lastActivityId = -99
While ($job.State -eq "Running")
{
$child = $job.ChildJobs[0]
#update the UI only if progress has started and the ActivityId has not already been reported on and the Progress report is one I care about
if ($child.Progress.Count -gt 0 -and $child.Progress[$child.Progress.Count - 1].ActivityId -ne $lastActivityId -and ($child.Progress[$child.Progress.Count - 1]).StatusDescription -eq "Reporting")
{
write-host "=============================="
write-host "in progress updates"
write-host "=============================="
#use the progress properties, i.e., RecordType and PercentComplete to update the UI
$child.Progress[$child.Progress.Count - 1]
#store this Id so we can ignore progress until Id changes
$lastActivityId = $child.Progress[$child.Progress.Count - 1].ActivityId
}
#period at which the UI is updated
start-sleep -milliseconds 250
}
$retObj = Receive-Job -Name "UniqueJobName"
write-host "=============================="
write-host "receive job"
write-host "=============================="
# Because the job may finish before progress is captured
# for each item, use the returned values to update the UI one last time
foreach ($key in $retObj.GetEnumerator())
{
"retObj=" + $key.name + " " + $key.Value.status + " " + $key.Value.details
}
#cleanup
Get-Job -Name "UniqueJobName" | Stop-Job
Get-Job -Name "UniqueJobName" | Remove-Job
示例输出
==============================
in progress updates
==============================
ActivityId : 1
ParentActivityId : -1
Activity : For UI Update: Item A processing complete
StatusDescription : Reporting
CurrentOperation :
PercentComplete : 20
SecondsRemaining : -1
RecordType : Completed
==============================
in progress updates
==============================
ActivityId : 2
ParentActivityId : -1
Activity : For UI Update: Item B processing complete
StatusDescription : Reporting
CurrentOperation :
PercentComplete : 40
SecondsRemaining : -1
RecordType : Completed
==============================
in progress updates
==============================
ActivityId : 3
ParentActivityId : -1
Activity : For UI Update: Item C processing complete
StatusDescription : Reporting
CurrentOperation :
PercentComplete : 60
SecondsRemaining : -1
RecordType : Completed
==============================
in progress updates
==============================
ActivityId : 4
ParentActivityId : -1
Activity : For UI Update: Item D processing complete
StatusDescription : Reporting
CurrentOperation :
PercentComplete : 80
SecondsRemaining : -1
RecordType : Completed
==============================
receive job
==============================
retObj=Item D PASS
retObj=Item E PASS
retObj=Item A FAIL some error description
retObj=Item B FAIL some error description
retObj=Item C PASS
文章来源: How can I keep the UI responsive and updated with progress while all the work is done in a background job on the local computer?