Powershell: обновление графического интерфейса пользователя из результатов фоновой работы - PullRequest
0 голосов
/ 11 декабря 2018

РЕДАКТИРОВАТЬ: Я смог заставить его работать, см. Мое решение ниже.Приведенные ниже комментарии верны, что Powershell на самом деле не идеален для графического интерфейса и многопоточности, но это можно сделать.


У меня есть форма в Powershell, которая использует Start-Job для запуска функций вфон без зависания графического интерфейса.Моя цель - постоянно проверять состояние этих заданий на предмет их вывода.Мне удалось использовать таймер Windows Forms, чтобы проверить результаты работы и соответствующим образом обновить графический интерфейс.

Все работает нормально, но кажется неаккуратным.Это лучший способ обновления графического интерфейса?Я относительно новичок в Powershell и хочу улучшить свое кодирование.

Пример того, что я делаю:

$jobScript = {
    Start-Sleep 5
    Write-Output "The job has finished running"
}

$timerScript = {
    $timer.Stop()
    $jobResult = Get-Job | Receive-Job -Keep
    if ($jobResult) {
        $btn.text = $jobResult
    } else {
        $timer.Start()
    }
}

Add-Type -AssemblyName System.Windows.Forms
$form             = New-Object System.Windows.Forms.Form
$form.ClientSize  = '300,300'
$form.topmost     = $true

$btn              = New-Object System.Windows.Forms.Button
$btn.Text         = "The job is still running"
$btn.Width        = 300
$btn.Height       = 300
$form.Controls.Add($btn)

$timer            = New-Object System.Windows.Forms.Timer
$timer.Interval   = 100
$timer.add_Tick($timerScript)
$timer.Start()

Start-Job -ScriptBlock $jobScript

$form.ShowDialog()

Обновление: мое решение

Использование Register-ObjectEvent не сработало, казалось, что оно борется с графическим интерфейсом для потока.Вместо этого я смог использовать [System.Windows.Forms.Application]::DoEvents().Это позволяет перемещать графический интерфейс, и как только он будет перемещен, поток возобновится.Большое предостережение заключается в том, что выполнение приостанавливается до тех пор, пока перемещается графический интерфейс, поэтому, если ваш код должен реагировать на фоновое задание в течение определенного времени, это может вызвать ошибки.

Пример блока кода:

$jobScript =
{
    Start-Sleep 5
    Write-Output "The job is completed"
}

Add-Type -AssemblyName System.Windows.Forms
$form             = New-Object System.Windows.Forms.Form
$form.ClientSize  = '300,300'
$form.topmost     = $true

$btn              = New-Object System.Windows.Forms.Button
$btn.Text         = "..."
$btn.Width        = 300
$btn.Height       = 300
$form.Controls.Add($btn)

$btn.add_click({
    $btn.Text = "Starting job"
    $jobby = Start-Job -ScriptBlock $jobScript
    Do {[System.Windows.Forms.Application]::DoEvents()} Until ($jobby.State -eq "Completed")
    $btn.Text = Get-Job | Receive-Job
})

$form.ShowDialog()

Ответы [ 2 ]

0 голосов
/ 11 декабря 2018

Вы можете использовать события:

 $job = Start-Job {sleep 3; Write-Output "Dummy job completed"}

$callback = {

Write-Host "Event Fired"
Unregister-Event -SourceIdentifier "DummyJob"
Write-Host ($job | Receive-Job)

}

$evt = Register-ObjectEvent -InputObject $job -EventName StateChanged -SourceIdentifier "DummyJob" -Action $callback 


# to remove all 
Get-Job | Remove-Job -Force # jobs and events
Get-EventSubscriber | Unregister-Event  # events
0 голосов
/ 11 декабря 2018

Возможно, вы захотите опубликовать это на CodeReview.StackExchange.com .

Я ненавижу, когда люди создают пользовательский интерфейс в Powershell.Если вам нужно правильное приложение для форм Windows, просто напишите его на C #.Поэтому я не согласен с дизайном в его предпосылке.

Мне нравится ваш импульс отойти от дизайна опроса;Вы начинаете работу, а затем опрашиваете, чтобы увидеть, завершена ли она.Я думаю, что обработчик событий может быть лучшим выбором.Ознакомьтесь с разделом «Мониторинг фонового задания» в статье PowerShell и события: события объекта .Это старенький, но вкусный.

...