关闭 PowerShell GUI 很笨重,无法在倒计时时四处拖动或单击“取消”按钮

Shutdown PowerShell GUI is clunky to drag around or click the Cancel button whilst counting down

你好 PoSh Gurus 和博学的民间人士;我最近创建了一个简单的关机 GUI,用于在关机前 30 分钟进行倒计时。它运行良好,但我正在寻找提高脚本性能的方法。

问题: 当计数器滴答作响时,显示倒计时滴答声的标签工作正常。但是,当我尝试移动 window 时,拖动 window 会出现延迟,当我单击“取消”时,从我单击“取消”到表单关闭几乎有 1 秒的延迟。任何关于如何调整代码甚至完全废弃代码并从头开始工作的想法都会很受欢迎:)

非常感谢您的帮助!

function GenerateForm {   
#region Import the Assemblies
[reflection.assembly]::loadwithpartialname("System.Windows.Forms") | Out-Null
[reflection.assembly]::loadwithpartialname("System.Drawing") | Out-Null
#endregion

#region Generated Form Objects
$frmShutdown = New-Object System.Windows.Forms.Form
$grpBody = New-Object System.Windows.Forms.GroupBox
$lblCounter = New-Object System.Windows.Forms.Label
$lblShutdowntime = New-Object System.Windows.Forms.Label
$lblMessage = New-Object System.Windows.Forms.Label
$btnCancel = New-Object System.Windows.Forms.Button
$lblTitle = New-Object System.Windows.Forms.Label
$InitialFormWindowState = New-Object System.Windows.Forms.FormWindowState
#endregion Generated Form Objects

#----------------------------------------------
#Generated Event Script Blocks
#----------------------------------------------
#Provide Custom Code for events specified in PrimalForms.
$btnCancel_OnClick= 
{
#TODO: Place custom script here
   [System.Windows.Forms.Application]::DoEvents()
   $btnCancel.Enabled = $false
}

$OnLoadForm_StateCorrection=
{#Correct the initial state of the form to prevent the .Net maximized form issue
    $frmShutdown.WindowState = $InitialFormWindowState
}

$OnLoadForm_LoadControls=
{
    [int]$s = 59
    [int]$m = 29
    $script:CancelLoop = $false
    [System.Windows.Forms.Application]::DoEvents()
    Do
    {        
        [System.Windows.Forms.Application]::DoEvents()
        $lblCounter.Text = "$m minutes $s seconds"
        Sleep -seconds 1
        if($s -lt 1){$m--;$s=60}
        If($btnCancel.Enabled -eq $false)
        {
            $cancel = $true
            break            
        }
        $s--
    }While(($m -ge 0))
    If(!($cancel)){Stop-Computer}
    $frmShutdown.Close()    
}

#----------------------------------------------
#region Generated Form Code
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 269
$System_Drawing_Size.Width = 536
$frmShutdown.ClientSize = $System_Drawing_Size
$frmShutdown.DataBindings.DefaultDataSourceUpdateMode = 0
$frmShutdown.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",18,0,3,1)
$frmShutdown.FormBorderStyle = 5
$frmShutdown.Name = "frmShutdown"
$frmShutdown.Text = "SHUTDOWN IN PROGRESS"


$grpBody.DataBindings.DefaultDataSourceUpdateMode = 0
$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 25
$System_Drawing_Point.Y = 45
$grpBody.Location = $System_Drawing_Point
$grpBody.Name = "grpBody"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 145
$System_Drawing_Size.Width = 499
$grpBody.Size = $System_Drawing_Size
$grpBody.TabIndex = 3
$grpBody.TabStop = $False

$frmShutdown.Controls.Add($grpBody)
$lblCounter.DataBindings.DefaultDataSourceUpdateMode = 0
$lblCounter.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",15.75,0,3,1)
$lblCounter.ForeColor = [System.Drawing.Color]::FromArgb(255,255,0,0)

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 222
$System_Drawing_Point.Y = 106
$lblCounter.Location = $System_Drawing_Point
$lblCounter.Name = "lblCounter"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 29
$System_Drawing_Size.Width = 236
$lblCounter.Size = $System_Drawing_Size
$lblCounter.TabIndex = 4
$lblCounter.Text = ""

$grpBody.Controls.Add($lblCounter)

$lblShutdowntime.DataBindings.DefaultDataSourceUpdateMode = 0
$lblShutdowntime.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",14.25,0,3,1)

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 22
$System_Drawing_Point.Y = 107
$lblShutdowntime.Location = $System_Drawing_Point
$lblShutdowntime.Name = "lblShutdowntime"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 26
$System_Drawing_Size.Width = 194
$lblShutdowntime.Size = $System_Drawing_Size
$lblShutdowntime.TabIndex = 3
$lblShutdowntime.Text = "Shutdown will start in: 30 minutes 00 seconds"

$grpBody.Controls.Add($lblShutdowntime)

$lblMessage.DataBindings.DefaultDataSourceUpdateMode = 0
$lblMessage.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",11.25,0,3,1)
$lblMessage.ForeColor = [System.Drawing.Color]::FromArgb(255,0,0,0)

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 22
$System_Drawing_Point.Y = 21
$lblMessage.Location = $System_Drawing_Point
$lblMessage.Name = "lblMessage"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 73
$System_Drawing_Size.Width = 463
$lblMessage.Size = $System_Drawing_Size
$lblMessage.TabIndex = 2
$lblMessage.Text = "This computer is going to be shut down.  If you are using this computer and wish to abort the shutdown, please click Cancel below."
$lblMessage.TextAlign = 32

$grpBody.Controls.Add($lblMessage)



$btnCancel.DataBindings.DefaultDataSourceUpdateMode = 0

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 208
$System_Drawing_Point.Y = 199
$btnCancel.Location = $System_Drawing_Point
$btnCancel.Name = "btnCancel"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 58
$System_Drawing_Size.Width = 146
$btnCancel.Size = $System_Drawing_Size
$btnCancel.TabIndex = 1
$btnCancel.Text = "CANCEL"
$btnCancel.UseVisualStyleBackColor = $True
$btnCancel.Add_Click($btnCancel_OnClick)
#$btnCancel.add_Click($btnCancel_OnClick)

$frmShutdown.Controls.Add($btnCancel)

$lblTitle.DataBindings.DefaultDataSourceUpdateMode = 0
$lblTitle.Font = New-Object System.Drawing.Font("Microsoft Sans Serif",18,1,3,1)
$lblTitle.ForeColor = [System.Drawing.Color]::FromArgb(255,255,0,0)

$System_Drawing_Point = New-Object System.Drawing.Point
$System_Drawing_Point.X = 47
$System_Drawing_Point.Y = 9
$lblTitle.Location = $System_Drawing_Point
$lblTitle.Name = "lblTitle"
$System_Drawing_Size = New-Object System.Drawing.Size
$System_Drawing_Size.Height = 40
$System_Drawing_Size.Width = 447
$lblTitle.Size = $System_Drawing_Size
$lblTitle.TabIndex = 0
$lblTitle.Text = "SYSTEM SHUTDOWN SCHEDULED"

$frmShutdown.Controls.Add($lblTitle)

#endregion Generated Form Code

#Save the initial state of the form
$InitialFormWindowState = $frmShutdown.WindowState
#Init the OnLoad event to correct the initial state of the form
$frmShutdown.add_Load($OnLoadForm_StateCorrection)
$frmShutdown.TopMost = $True
$frmShutdown.StartPosition = "CenterScreen"
$frmShutdown.ControlBox = $False
$frmShutdown.MaximizeBox = $False
$frmShutdown.add_Load($OnLoadForm_LoadControls)

#$frmShutdown.Modal = system
#Show the Form
$frmShutdown.ShowDialog()| Out-Null

} #End Function

#Call the Function
GenerateForm

由于循环中的 Sleep,您看到了这些延迟。

尝试改用计时器。 Windows 将在给定的时间间隔内调用计时器,并在后台很好地执行您的命令。计时器不会中断用户界面上的操作。

所以让我们创建一个计时器。

先清理一下。

删除您的 $OnLoadForm_LoadControl 脚本块。你不会需要它。 也删除

$frmShutdown.add_Load($OnLoadForm_LoadControls)

你不需要它。

将以下内容放入您的脚本中:

$global:s = 59
$global:m = 1
$timer = New-Object System.Windows.Forms.Timer
$timer.Interval = 1000


$action = {
    $lblCounter.Text = "$global:m minutes $s seconds"
    if($s -lt 1){$global:m--;$global:s=60}
    If($btnCancel.Enabled -eq $false)
    {
        $cancel = $true      
    }
    $global:s--

    if ($global:m -eq 0 -and $global:s -eq 0)
    {
        #If(!($cancel)){Stop-Computer}
        $timer.Enabled = $false
        $frmShutdown.Close()    

    }

}
$timer.add_tick($action)

好的,这将创建一个 WinForm 计时器,但尚未启动它。

请注意,Stop-Computer 已被注释掉,因为您应该在执行该命令之前尝试此操作。 另请注意,$global:m 设置为 1 分钟,您需要将其更改为 29 分钟。

在脚本底部 $frmShutdown.ShowDialog()| Out-Null 之前添加:

$timer.Start()

计时器将启动,您的消息标签应该正在更新。 您可以单击“取消”或毫无延迟地移动您的 window。