Forms Powershell:从后台作业结果更新GUI
编辑:我能够让它工作,请参阅下面的解决方案。下面的评论是正确的,Powershell并不是GUI和线程的理想选择,但它是可以做到的Forms Powershell:从后台作业结果更新GUI,forms,powershell,user-interface,timer,jobs,Forms,Powershell,User Interface,Timer,Jobs,编辑:我能够让它工作,请参阅下面的解决方案。下面的评论是正确的,Powershell并不是GUI和线程的理想选择,但它是可以做到的 我在Powershell中有一个表单,它使用Start Job在后台运行函数,而不冻结GUI。我的目标是不断检查这些工作的产出状态。我设法使用Windows窗体计时器来检查作业的结果,并相应地更新GUI 这一切都很好,但它似乎马虎。这是完成GUI刷新的最佳方法吗?我对Powershell比较陌生,我想改进我的编码 我正在做的示例: $jobScript = {
我在Powershell中有一个表单,它使用Start Job在后台运行函数,而不冻结GUI。我的目标是不断检查这些工作的产出状态。我设法使用Windows窗体计时器来检查作业的结果,并相应地更新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中构建UI。如果您想要一个合适的Windows窗体应用程序,只需用C#编写即可。所以我不同意这个设计的前提 我喜欢你离开投票站设计的冲动;您启动作业,然后轮询以查看作业是否已完成。我认为事件处理程序可能是更好的选择。查看文章中的“监视后台作业”部分。这是一个古老而美好的故事。您可以使用事件:
$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
PowerShell显示进度的方式是使用
写入进度
。请参阅Get Help Write Progress-examples
@KoryGill With winform applications它不是。@KoryGill感谢您的回复。我真正的问题是,如何让表单在后台作业返回结果后等待并更新,无论是使用写入进度
还是使用写入输出
在Powershell中制作响应性winforms GUI都是一件非常痛苦的事。我会考虑和其他用户互动的方式。非常感谢你的回复和链接。请你扩展一下为什么你不喜欢PuxBug GUI?我想这只是一种变通方法,而不是预期用途?这是一个很好的问题。我可以用我的自行车发电。这种方法可以让我保持健康,而且更环保。Powershell的UI有点像这样。我能做到。它使UI开发更容易访问,特别是对于Powershell开发人员。然而,Powershell并不是为了达到这个目的,在GUI竞技场上也没有太多的游戏时间。出于这个原因,你会发现你在兔子洞里钻得越深,你就会发现小陷阱。如果你坚持使用为UI开发设计的语言,你会遇到更少的麻烦。对不起,我不得不简短地说;字符限制。很好的类比,再次感谢您的时间。我最终找到了一个更好的解决方案(我会编辑我的OP),但我肯定会开始用其他语言为未来做准备。你可以用C#做你能做的一切。您可以在PoSh中构建非常好的UI(示例:)。与使用c#相比,它不那么复杂,工作量也更少。谢谢!在我开始使用C#之前,我会一直把它作为一种解决方法来研究,我一直听说我应该这样做。使用它进行一些测试,Register ObjectEvent
在使用winforms时会产生奇怪的结果。我在谷歌上搜索了一下,它似乎在与表单争夺线程。我将用最终找到的解决方案更新OP。