我编写了一个自定义 Start-SleepNoUIHang
函数来休眠 Windows 窗体 UI,同时不挂起它以允许用户使用 ForEach
循环进行交互,并在该循环内调用 [System.Windows.Forms.Application]::DoEvents()
阻止它这样做。
它按我的预期工作,但唯一的问题是该函数稍微偏离了参数 $Milliseconds
。
如果我将其设置为 5000
,则计时器大约需要 6300
毫秒。
我曾尝试在 ForEach
循环中添加一个计数器,然后在到达 $Milliseconds
参数时中断它,但这似乎不起作用。
我不想使用 .net 计时器,因此我将其创建为单行程序,以便在程序中需要它的任何地方使用。
这里的任何帮助将不胜感激。
这是代码(带注释):
<#
This function attempts to pause the UI without hanging it without the need for a
timer event that does work.
The only trouble is that the timer slight drifts more than the provided
$Milliseconds argument.
#>
function Start-SleepNoUIHang {
Param
(
[Parameter(Mandatory = $false, HelpMessage = 'The time to wait in milliseconds.')]
[int]$Milliseconds
)
$timeBetween = 50 # This value seems to be a good value in order for the UI not to hang itself.
$timeElapsed = 0 # Increment this to check and break out of the ForEach loop.
# ($Milliseconds/$timeBetween)*$timeBetween # Time is the total wait time in milliseconds.
1..($Milliseconds/$timeBetween) | ForEach {
Start-Sleep -Milliseconds $timeBetween
Try { [System.Windows.Forms.Application]::DoEvents() } catch{} # A try catch here in case there's no windows form.
$timeElapsed = $timeElapsed + $timeBetween # Increment the $timeElapsed counter.
Write-Host $timeElapsed
# This doesn't seem to have any effect on the timer. It ends on its own accord.
if ($timeElapsed -gt $Milliseconds) {
Write-Host 'Break'
break
}
}
}
$elapsed = [System.Diagnostics.Stopwatch]::StartNew()
Write-Host "Started at $(get-date)"
Start-SleepNoUIHang -Milliseconds 5000
Write-Host "Ended at $(get-date)"
Write-Host "Total Elapsed Time: $($elapsed.Elapsed.ToString())"
我也尝试用 While 循环替换 ForEach 循环,但行为相同。
While ( $Milliseconds -gt $timeElapsed ) {
$timeElapsed = $timeElapsed + $timeBetween # Increment the $timeElapsed counter.
Start-Sleep -Milliseconds $timeBetween
Write-Host $timeElapsed
}