If I run the following code, the Event Action is executed:
$Job = Start-Job {'abc'}
Register-ObjectEvent -InputObject $Job -EventName StateChanged `
-Action {
Start-Sleep -Seconds 1
Write-Host '*Event-Action*'
}
The string 'Event-Action' is displayed.
If I use a Form and start the above code by clicking a button,
the Event Action is not executed:
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$Form1 = New-Object Windows.Forms.Form
$Form1.Add_Shown({
$Form1.Activate()
})
$Button1 = New-Object System.Windows.Forms.Button
$Button1.Text = 'Test'
$Form1.Controls.Add($Button1)
$Button1.Add_Click({
Write-Host 'Test-Button was clicked'
$Job = Start-Job {'abc'}
Register-ObjectEvent -InputObject $Job -EventName StateChanged `
-Action {
Start-Sleep -Seconds 1
Write-Host '*Event-Action*'
}
})
$Form1.ShowDialog()
Only when I click the button again, the first Event Action is executed.
With the third click the second Event Action is executed and so on.
If I do multiple clicks in rapid succession, the result is unpredictable.
Furthermore when I close the form with the button in the upper right corner,
the last "open" Event Action is executed.
Note: For testing PowerShell ISE is to be preferred, because PS Console displays
the string only under certain circumstances.
Can someone please give me a clue what's going on here?
Thanks in advance!
nimizen.
Thanks for your explanation, but I don't really understand, why the StateChanged event is not fired or visible to the main script until there is some action with the Form. I'd appreciate another attempt to explain it to me.
What I want to accomplish is a kind of multithreading with PowerShell and Forms.
My plan is the following:
'
The script shows a Form to the user.
The user does some input and clicks a button.
Based on the user's input a set of Jobs are started with Start-Job and a StateChanged event is registered for each job.
While the Jobs are running, the user can perform any action on the Form (including stop the Jobs via a button) and the Form is repainted when necessary.
The script reacts to any events which are fired by the Form or its child controls.
Also the script reacts to each job's StateChanged event.
When a StateChanged event occurs, the state of each job is inspected, and if all jobs have the state 'Completed', the jobs' results are fetched with Receive-Job and displayed to the user.
'
All this works fine except that the StateChanged event is not visible to the main script.
The above is still my favorite solution and if you have any idea how to implement this, please let me know.
Otherwise I'll most likely resort to a workaround, which at least gives the user a multithreading feeling. It is illustrated in the following example:
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")
$Form1 = New-Object Windows.Forms.Form
$Form1.Add_Shown({
$Form1.Activate()
})
$Button1 = New-Object System.Windows.Forms.Button
$Button1.Text = 'Test'
$Form1.Controls.Add($Button1)
$Button1.Add_Click({
$Form1.Focus()
Write-Host 'Test-Button was clicked'
$Job = Start-Job {Start-Sleep -Seconds 1; 'abc'}
Do {
Start-Sleep -Milliseconds 100
Write-Host 'JobState: ' $Job.State
[System.Windows.Forms.Application]::DoEvents()
}
Until ($Job.State -eq 'Completed')
Write-Host '*Action*'
})
$Form1.ShowDialog()
See Question&Answers more detail:
os