Powershell:根据后台作业结果更新GUI

时间:2018-12-10 22:08:21

标签: forms powershell user-interface timer jobs

编辑:我能够使它工作,请参见下面的解决方案。下面的评论者是正确的,因为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()

2 个答案:

答案 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