【发布时间】:2019-05-11 20:52:20
【问题描述】:
编辑:我能够让它工作,请参阅下面的解决方案。下面的评论是正确的,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()
【问题讨论】:
-
显示进度的 PowerShell 方法是使用
Write-Progress。见Get-Help Write-Progress -examples。 -
@KoryGill 对于 winform 应用程序则不然。
-
@KoryGill 感谢您的回复。我真正的问题是如何在后台作业返回结果后让表单等待和更新,无论是
Write-Progress还是Write-Output -
在 Powershell 中制作一个响应式的 winforms GUI 真的很痛苦。我会考虑与用户互动的其他方式。
标签: forms powershell user-interface timer jobs