Rejeter un formulaire PowerShell contrôlé par une tâche de démarrage
-
12-11-2019 - |
Question
J'ai été chargé de construire un script PowerShell avec une interface graphique qui permet aux utilisateurs d'installer des imprimantes réseau. J'ai réussi à le faire, mais je ne peux pas répondre à l'exigence selon laquelle l'utilisateur est affiché une fenêtre «s'il vous plaît patinez» pendant que les imprimantes installent. Si je passe à la fenêtre à partir du fil principal, l'interface graphique est suspendue. Si je bouge en montrant la fenêtre à un travail séparé, je ne suis plus en mesure de fermer la fenêtre. Voici ma tentative:
$waitForm = New-Object 'System.Windows.Forms.Form'
$CloseButton_Click={
# open "please wait form"
Start-Job -Name waitJob -ScriptBlock $callWork -ArgumentList $waitForm
#perform long-running (duration unknown) task of adding several network printers here
$max = 5
foreach ($i in $(1..$max)){
sleep 1 # lock up the thread for a second at a time
}
# close the wait form - doesn't work. neither does remove-job
$waitForm.Close()
Remove-Job -Name waitJob -Force
}
$callWork ={
param $waitForm
[void][reflection.assembly]::Load("System.Windows.Forms, Version=2.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089")
$waitForm = New-Object 'System.Windows.Forms.Form'
$labelInstallingPrintersPl = New-Object 'System.Windows.Forms.Label'
$waitForm.Controls.Add($labelInstallingPrintersPl)
$waitForm.ClientSize = '502, 103'
$labelInstallingPrintersPl.Location = '25, 28'
$labelInstallingPrintersPl.Text = "Installing printers - please wait..."
$waitForm.ShowDialog($this)
}
Est-ce que quelqu'un sait comment je peux rejeter la fenêtre $ Wattform lorsque la tâche de longue durée s'est terminée?
La solution
Vous pouvez essayer d'exécuter la boîte de dialogue Windows Forms sur le thread principal et effectuer le travail réel en arrière-plan:
Add-Type -Assembly System.Windows.Forms
$waitForm = New-Object 'System.Windows.Forms.Form'
$labelInstallingPrintersPl = New-Object 'System.Windows.Forms.Label'
$waitForm.Controls.Add($labelInstallingPrintersPl)
$waitForm.ClientSize = '502, 103'
$labelInstallingPrintersPl.Location = '25, 28'
$labelInstallingPrintersPl.Text = "Installing printers - please wait..."
$waitForm.ShowDialog($this)
Start-Job -ScriptBlock $addPrinters | Wait-Job
$waitForm.Close()
$addPrinters = {
$max = 5
foreach ($i in $(1..$max)) {
sleep 1 # lock up the thread for a second at a time
}
}
Autres conseils
Cette première réponse était correcte, créez le formulaire sur le thread principal et effectuez la longue tâche en cours d'exécution sur un thread séparé. La raison pour laquelle il n'exécute pas le code principal avant que le formulaire ne soit rejeté parce que vous utilisez la méthode «showDialog» du formulaire, cette méthode augmente l'exécution de code ultérieure jusqu'à ce que le formulaire soit fermé.
Au lieu de cela, utilisez la méthode «Show», l'exécution de code se poursuivra, vous devriez probablement inclure certains gestionnaires d'événements pour éliminer le formulaire
Add-Type -Assembly System.Windows.Forms
$waitForm = New-Object 'System.Windows.Forms.Form'
$labelInstallingPrintersPl = New-Object 'System.Windows.Forms.Label'
$waitForm.Controls.Add($labelInstallingPrintersPl)
$waitForm.ClientSize = '502, 103'
$labelInstallingPrintersPl.Location = '25, 28'
$labelInstallingPrintersPl.Text = "Installing printers - please wait..."
$waitForm.Add_FormClosed({
$labelInstallingPrintersPl.Dispose()
$waitForm.Dispose()
})
$waitForm.Show($this)
Start-Job -ScriptBlock $addPrinters | Wait-Job
$waitForm.Close()
$addPrinters = {
$max = 5
foreach ($i in $(1..$max)) {
sleep 1 # lock up the thread for a second at a time
}
}
Que diriez-vous d'ajouter un Windows.forms.progressbar à la fenêtre GUI principale? Mettez à jour sa valeur étape par étape lors de l'ajout d'imprimantes, les utilisateurs verront donc que l'application fonctionne.