Search code examples
winformspowershelltimer

How to add a timer in powershell to quit the form after certain amount of time


I have created a form (still in progress) in PowerShell that has radio buttons, which I want to display on the screen for a certain amount of time, and if that time has elapsed, it would send an email and close the form. It is not clear to me how to add the timer to the form, the rest I can figure it out.

$RadioButtonList = @( "Tom", "Dick", "Harry", "John", "Jane" )

$RadioButtonYMargin = 10
$RadioButtonIndex = 0
$RadioButtonX = 20
$RadioButtonY = (10 + $RadioButtonYMargin)
$RadioButtonYOffset = 30
$RadioButtonWidth = 350
$RadioButtonHeight = 20

$GroupBoxXMargin = 7
$GroupBoxX = 20
$GroupBoxY = 30
$GroupBoxWidth = 400
$GroupBoxHeight = $RadioButtonY + ( $RadioButtonList.Count * ( $RadioButtonHeight + 9 )) + $RadioButtonYMargin

$ButtonYMargin = 50
$ButtonY = $GroupBoxY + $GroupBoxHeight + $ButtonYMargin
$ButtonWidth = 100
$ButtonHeight = 40

$FormWidth = $GroupBoxWidth + (($GroupBoxX + $GroupBoxXMargin) * 2)
$FormHeight = $GroupBoxY + $GroupBoxHeight +  $ButtonHeight + ($ButtonYMargin * 2)

$ButtonXSpacing = 50
$ButtonXMargin = [Int](($FormWidth - (($ButtonWidth * 2) + $ButtonXSpacing)) / 2)

Function RadioButtonClick ( $RadioButtonSelected ) {
    $Form.AcceptButton.Enabled = $True
}

[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
[void] [System.Reflection.Assembly]::LoadWithPartialName("System.Drawing") 

# Set the size of your form
$Form = New-Object System.Windows.Forms.Form
$Form.Width = $FormWidth
$Form.Height = $FormHeight
$Form.Text = "Operator, acknowledge your presence"

# Set the font of the text to be used within the form
$Font = New-Object System.Drawing.Font("Times New Roman",12)
$Form.Font = $Font

# Create a group that will contain your radio buttons
$GroupBox = New-Object System.Windows.Forms.GroupBox
$GroupBox.Location = New-Object System.Drawing.Size( $GroupBoxX, $GroupBoxY )
$GroupBox.size = New-Object System.Drawing.Size( $GroupBoxWidth, $GroupBoxHeight )
$GroupBox.text = "Please select your name below:"

While (  $RadioButtonIndex -lt $RadioButtonList.Count ) {
    $RadioButton = New-Object System.Windows.Forms.RadioButton
    $RadioButton.Location = New-Object System.Drawing.Size( $RadioButtonX, $RadioButtonY )
    $RadioButton.Size = New-Object System.Drawing.Size( $RadioButtonWidth, $RadioButtonHeight )
    $RadioButton.Checked = $False
    $RadioButton.Text = $RadioButtonList[ $RadioButtonIndex ]
    $RadioButtonY += $RadioButtonYOffset
    $RadioButton.Add_Click({ RadioButtonClick $This.Text })
    $GroupBox.Controls.Add( $RadioButton )
    $RadioButtonIndex += 1
}

# Add an OK button
$OKButton = New-Object System.Windows.Forms.Button
$OKButton.Location = New-Object System.Drawing.Size( $ButtonXMargin, $ButtonY )
$OKButton.Size =  New-Object System.Drawing.Size( $ButtonWidth, $ButtonHeight )
$OKButton.Text = 'OK'
$OKButton.Enabled = $False
$OKButton.DialogResult=[System.Windows.Forms.DialogResult]::OK

# Add a cancel button
$CancelButton = New-Object System.Windows.Forms.Button
$CancelButton.Location = New-Object System.Drawing.Size( ($ButtonXMargin + $ButtonWidth + $ButtonXSpacing), $ButtonY )
$CancelButton.Size =  New-Object System.Drawing.Size( $ButtonWidth, $ButtonHeight )
$CancelButton.Text = "Cancel"
$CancelButton.DialogResult=[System.Windows.Forms.DialogResult]::Cancel

# Add all the Form controls on one line 
$Form.Controls.AddRange(@($GroupBox,$OKButton,$CancelButton))


# Assign the Accept and Cancel options in the form to the corresponding buttons
$Form.AcceptButton = $OKButton
$Form.CancelButton = $CancelButton

# Activate the form
$Form.Add_Shown({$Form.Activate()})    

# Get the results from the button click
$dialogResult = $Form.ShowDialog()
# If the OK button is selected
if ($dialogResult -eq "OK") {
    $SelectedRadioButton = ($GroupBox.Controls | Where-Object{$_.Checked}).Text
    Write-Host "Selection was $SelectedRadioButton"
} Else {
    Write-Host "Cancelled"
}

Solution

  • Here's a minimal example that shows how to use a timer to automatically close a WinForms form after 2 seconds (PSv5+ syntax):

    using namespace System.Windows.Forms
    Add-Type -AssemblyName System.Windows.Forms
    
    # Create the form.
    $form = [Form]::new()
    
    # Create a timer.
    $timer = [Timer]::new()
    $timer.Interval = 2000 # 2 seconds
    
    # Set up the event handler for the timer.
    $timer.Add_Tick({
        # Close the form.
        # Note: We dispose (stop) the timer later, right after the form closes;
        #       with a very short interval, another tick event could fire before
        #       that happens, but calling .Close() on an already closed form is fine.
        $form.Close()
    })
    
    # Start the timer.
    $timer.Start()
    
    # Show the dialog, which will automatically close
    # when the timer fires.
    $result = $form.ShowDialog()
    
    # Dispose (stop) the timer. Doing this here instead of in the tick
    # event handler ensures that the timer is stopped even when the form 
    # was closed by the user.
    $timer.Dispose() 
    
    # Dispose the form and its controls. Skip, if you want to redisplay the form later.
    $form.Dispose()  
    

    Note the need for $form.Dispose(), because the form was shown as a modal dialog with .ShowDialog() (rather than .Show()), in which case closing it does not implicitly dispose it - see this answer for details.


    PSv4- syntax (where using namespace and ::new() aren't available):

    Add-Type -AssemblyName System.Windows.Forms
    
    # Create the form.
    $form = New-Object System.Windows.Forms.Form
    
    # Create a timer.
    $timer = New-Object System.Windows.Forms.Timer
    $timer.Interval = 2000 # 2 seconds
    
    # Set up the event handler for the timer.
    $timer.Add_Tick({
        # Close the form.
        # Note: We dispose (stop) the timer later, right after the form closes;
        #       with a very short interval, another tick event could fire before
        #       that happens, but calling .Close() on an already closed form is fine.
        $form.Close()
    })
    
    # Start the timer.
    $timer.Start()
    
    # Show the dialog, which will automatically close
    # when the timer fires.
    $result = $form.ShowDialog()
    
    # Dispose (stop) the timer. Doing this here instead of in the tick
    # event handler ensures that the timer is stopped even when the form 
    # was closed by the user.
    $timer.Dispose() 
    
    # Dispose the form and its controls. Skip, if you want to redisplay the form later.
    $form.Dispose()