Powershell窗体-使用按钮暂停循环
我有一个基于表单的脚本,可以从各种来源复制大量文件。复制文件的主循环可以运行很长时间,我想添加一个暂停按钮来保持处理(直到再次按下暂停按钮) 按照建议,我正在使用Powershell窗体-使用按钮暂停循环,powershell,Powershell,我有一个基于表单的脚本,可以从各种来源复制大量文件。复制文件的主循环可以运行很长时间,我想添加一个暂停按钮来保持处理(直到再次按下暂停按钮) 按照建议,我正在使用[System.Windows.Forms.Application]::DoEvents()来保持表单的响应性,并提供一种在需要时优雅地中断复制循环的方法 我正努力想知道如何引入一个按钮来暂停“ForEach”循环,而不是打断它——当我尝试使用Do-Until/While时,是否有人能为我指出正确的方向,因为它似乎以某种方式挂起了脚本
[System.Windows.Forms.Application]::DoEvents()
来保持表单的响应性,并提供一种在需要时优雅地中断复制循环的方法
我正努力想知道如何引入一个按钮来暂停“ForEach”循环,而不是打断它——当我尝试使用Do-Until/While时,是否有人能为我指出正确的方向,因为它似乎以某种方式挂起了脚本
下面是我正在做的一个大大简化的示例:
$StartCopyButton.Add_Click({
$script:CancelLoop = $false
$script:PauseToggle = $false
$CancelButton.Enabled = $true
$StartCopyButton.Enabled = $false
Get-ChildItem -LiteralPath $Source -Recurse -File | ForEach {
Copy-Item -Path $.FullName -Destination $NewDestination
[System.Windows.Forms.Application]::DoEvents()
If($script:CancelLoop -eq $true) {
#Exit the loop
Break;
}
If ($script:PauseToggle) {
Do {
[System.Windows.Forms.Application]::DoEvents()
} Until (!$script:PauseToggle)
}
}
$CancelButton.Enabled = $false
$StartCopyButton.Enabled = $true
})
$CancelButton.Add_Click({
$script:CancelLoop = $true
})
$PauseButton.Add_Click({
# Boolean change value to true/false
$script:PauseToggle = !$script:PauseToggle
})
您可以检查暂停状态,如果它为真,则使用DoEvents执行空循环。像这样(虽然没有测试): 实际上,启动和暂停只需要一个按钮。这里有一个非常基本的方法来说明我的想法,没有经过测试:
$script:CancelLoop = $false
$script:PauseLoop = $false
$CopyButton.Add_Click({
# toggle the start/pause state when clicked
$script:PauseLoop = -not $script:PauseLoop
if ($script:PauseLoop) {
$CancelButton.Enabled = $false
$CopyButton.Text = "Start"
}
else {
$CancelButton.Enabled = $true
$CopyButton.Text = "Pause"
# start / resume the loop
Get-ChildItem $Source -Recurse -File | foreach {
$newPath = Join-Path $NewDestination $_.Name
# test if file was already copied
# (might want to compare modified times too)
if (-not (Test-Path $newPath)) {
Copy-Item $_.FullName $newPath
}
[System.Windows.Forms.Application]::DoEvents()
if ($script:CancelLoop -or $script:PauseLoop) {
# exit loop if cancelled or paused
break
}
}
$CancelButton.Enabled = $false
$CopyButton.Text = "Start"
}
})
另一种方法是首先获取所有文件,将它们保存在一个集合中,然后存储索引并在此时暂停/恢复。但这也带来了风险,即文件列表在此期间可能发生了变化。因此,一个真正“安全”的解决方案将更加复杂。在复制循环中创建一个循环,该循环在“停止”按钮切换为“活动”时处于活动状态。在该循环中
DoEvents
。不要忘记,您还需要在外部循环中执行DoEvents
。(还没有测试这是否真的有效,只是一个想法)是的,谢谢,我刚刚意识到我试图在错误的地方编写代码(在按钮而不是循环中)。我已经修改了上面的内容,这似乎是可行的,不过如果有更优雅的方式来编写代码,我很高兴听到。更优雅的方式是制作一个单独的工作线程。但是在Powershell中控制线程确实是一件痛苦的事情。如果您想要一个表单应用程序(然后使用c#或vb.net)或Powershell脚本,您应该下定决心。将这两个世界混为一谈并不那么有效。在表单应用程序中,您将使用辅助线程。在PowerShell中,你不会使用暂停按钮等。@marsze在PowerShell中编写GUI本身就是一种黑客行为:)要获得一个好的结果,需要付出很大的努力。是的,我刚刚就OPNice的想法发表了评论,但如果文件量很大,可能需要一些时间才能恢复。@montonero正如我所说的,混合这两个世界不会很好。只需跳过表单并将该命令输入PowerShell即可。你可以随时在那里暂停管道。编译一个文件列表并不实际——涉及数百万个文件,PS资源将成为一个问题。不久前,我用自己找到的解决方案编辑了我的原始帖子,但我喜欢一个暂停/停止按钮的想法。
$script:CancelLoop = $false
$script:PauseLoop = $false
$CopyButton.Add_Click({
# toggle the start/pause state when clicked
$script:PauseLoop = -not $script:PauseLoop
if ($script:PauseLoop) {
$CancelButton.Enabled = $false
$CopyButton.Text = "Start"
}
else {
$CancelButton.Enabled = $true
$CopyButton.Text = "Pause"
# start / resume the loop
Get-ChildItem $Source -Recurse -File | foreach {
$newPath = Join-Path $NewDestination $_.Name
# test if file was already copied
# (might want to compare modified times too)
if (-not (Test-Path $newPath)) {
Copy-Item $_.FullName $newPath
}
[System.Windows.Forms.Application]::DoEvents()
if ($script:CancelLoop -or $script:PauseLoop) {
# exit loop if cancelled or paused
break
}
}
$CancelButton.Enabled = $false
$CopyButton.Text = "Start"
}
})