Winforms and Timers

There’s been some discussion lately in the SAPIEN product forums about PrimalForms and timers. As you know, PowerShell v1.0 is essentially single-threaded.   This generally means that timers and asynchronous code won’t work. But you can use a simple timer in a Windows form. Here’s an example of how you might use such a timer.

procperfI created a simple form to display process performance information for the top 20 processes, based on working set.  You can look at the functions in the beginning of the script to see how I accomplished this, but that’s not the real point of this article. We want to look at timers.

The first thing you’ll realize when you work on a new PrimalForm is that there is no Timer control in the toolbox.  Don’t worry, that will eventually be corrected in a service release. But that doesn’t mean you can’t manually add it to your form.  Create your form normally and a script file. Open the file in PrimalScript and scroll down to the generated forms objects region. Just before the end of the region, add code to define the timer object.

 

$txtComputer = New-Object System.Windows.Forms.TextBox
$statusBar1 = New-Object System.Windows.Forms.StatusBar
 
#add the timer control
$timer1 = New-Object System.windows.Forms.Timer
#enable it
$timer1.Enabled=$True
 
#endregion Generated Form Objects

At the end of the generated form code, tie the object’s Tick event to a script block. In this script, I have a script block called $GetData.

#endregion Generated Form Code
 
#add the script block to execute when the timer interval expires
$timer1.add_Tick($GetData)

When the timer expires, this script block is executed. This script block is also executed when the form is first shown.

$GetData= 
{
    #stop the timer while data is refreshed
    $timer1.stop()
    
    $statusBar1.Text="Getting data..."
    
    $form1.Refresh()
    
    $griddata=Get-ProcPerf -computername $txtComputer.Text | sort "WS(MB)" -desc | select -first 20
    
    $array= New-Object System.Collections.ArrayList
    
    $array.AddRange($griddata)
    $DataGrid1.DataSource = $array
    
    $updated=Get-Date
    $statusBar1.text="Last updated {0} Refresh in {1} seconds" -f $updated,$comboRefresh.Text
    
    #set the timer interval
    $interval=$comboRefresh.Text -as [int]
    #interval must be in milliseconds
    $timer1.Interval = ($interval * 1000) #1 second time interval
    #start the timer
    $timer1.Start()
    
    $form1.Refresh()
 
}

The script block calls my function to get the data and populate the data grid. The timer is first stopped since I don’t want it counting down while PowerShell is working. After the data is presented, I get a value from the combo drop down and set that as the timer interval. Technically, I take that value and multiply it by 1000 because the timer interval must be in milliseconds. I then start the timer.

If you leave everything alone, when the timer expires, the $GetData script block is executed and the entire process repeats. I’ve also connected this script block to the Refresh button and the combobox’s SelectedIndexChange event, ensuring that if you pick a new timer interval it will get used.

You can download a zip file with the form and script here.

Oh…and as an added bonus, you’ll notice the controls resize with the form. But I’ll leave that discussion for another day.