编辑:我能够使它工作,请参见下面的解决方案。下面的评论者是正确的,因为Powershell并不是GUI和线程的理想选择,但可以做到。
我在Powershell中有一个表单,该表单使用Start-Job在后台运行功能而不冻结GUI。我的目标是不断检查这些作业的状态以获取其输出。我设法使用Windows Forms Timer来检查作业的结果并相应地更新GUI。
一切正常,但似乎草率。这是完成GUI刷新的最佳方法吗?我是Powershell的新手,我想改善自己的编码。
我正在做的事的例子:
$jobScript = {
Start-Sleep 5
Write-Output "The job has finished running"
}
$timerScript = {
$timer.Stop()
$jobResult = Get-Job | Receive-Job -Keep
if ($jobResult) {
$btn.text = $jobResult
} else {
$timer.Start()
}
}
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object System.Windows.Forms.Form
$form.ClientSize = '300,300'
$form.topmost = $true
$btn = New-Object System.Windows.Forms.Button
$btn.Text = "The job is still running"
$btn.Width = 300
$btn.Height = 300
$form.Controls.Add($btn)
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 100
$timer.add_Tick($timerScript)
$timer.Start()
Start-Job -ScriptBlock $jobScript
$form.ShowDialog()
更新:我的解决方案
使用Register-ObjectEvent
无效,似乎正在与GUI争用该线程。相反,我可以使用[System.Windows.Forms.Application]::DoEvents()
。这允许GUI到处移动,一旦完成移动,线程将继续。这里最大的警告是,只要移动了GUI,执行就会暂停,因此,如果您的代码需要在一定时限内对后台作业做出反应,则可能会导致错误。
示例代码块:
$jobScript =
{
Start-Sleep 5
Write-Output "The job is completed"
}
Add-Type -AssemblyName System.Windows.Forms
$form = New-Object System.Windows.Forms.Form
$form.ClientSize = '300,300'
$form.topmost = $true
$btn = New-Object System.Windows.Forms.Button
$btn.Text = "..."
$btn.Width = 300
$btn.Height = 300
$form.Controls.Add($btn)
$btn.add_click({
$btn.Text = "Starting job"
$jobby = Start-Job -ScriptBlock $jobScript
Do {[System.Windows.Forms.Application]::DoEvents()} Until ($jobby.State -eq "Completed")
$btn.Text = Get-Job | Receive-Job
})
$form.ShowDialog()
答案 0 :(得分:1)
您可能希望将其发布在CodeReview.StackExchange.com上。
当人们在Powershell中构建UI时,我有点讨厌。如果您想要一个合适的Windows窗体应用程序,只需用C#编写即可。所以我不同意这种设计。
我喜欢您摆脱投票设计的冲动;您启动作业,然后进行轮询以查看其是否完成。我认为事件处理程序可能是一个更好的选择。请查看文章PowerShell and Events: Object Events中的“监视后台作业”部分。这是老歌,但是好东西。
答案 1 :(得分:1)
您可以使用事件:
$job = Start-Job {sleep 3; Write-Output "Dummy job completed"}
$callback = {
Write-Host "Event Fired"
Unregister-Event -SourceIdentifier "DummyJob"
Write-Host ($job | Receive-Job)
}
$evt = Register-ObjectEvent -InputObject $job -EventName StateChanged -SourceIdentifier "DummyJob" -Action $callback
# to remove all
Get-Job | Remove-Job -Force # jobs and events
Get-EventSubscriber | Unregister-Event # events