Is there a way to send events to the parent job when using Start-WPFJob?

余生颓废 提交于 2019-12-13 07:49:06

问题


I would like to launch a non-blocking UI from a parent Powershell script and receive UI messages like button clicks from the child job. I have this kind of messaging working using WinForms, but I prefer to use ShowUI because of how much less code it takes to create a basic UI. Unfortunately, though, I haven't found a way to send messages back to the parent job using ShowUI.

[Works] Forwarding Events When Using Start-Job

Using Start-Job, forwarding events from a child to a parent job is rather straightforward. Here is an example:

$pj = Start-Job -Name "PlainJob" -ScriptBlock {
    Register-EngineEvent -SourceIdentifier PlainJobEvent -Forward
    New-Event -SourceIdentifier PlainJobEvent -MessageData 'My Message'
}

Wait-Event | select SourceIdentifier, MessageData | Format-List

As expected, it prints out:

SourceIdentifier : PlainJobEvent
MessageData      : My Message

[Does Not Work] Forwarding Events When Using Start-WPFJob

Using Start-WPFJob, on the other hand, does not seem to forward events from the child to the parent. Consider this example:

Import-Module ShowUI
$wj = Start-WPFJob -ScriptBlock {
    Register-EngineEvent -SourceIdentifier MySource -Forward

    New-Button "Button" -On_Click { 
        New-Event -SourceIdentifier MySource -MessageData 'MyMessage'
        }
}

Wait-Event | select SourceIdentifier, MessageData | Format-List

Running this example produces this window:

Clicking on the button, however, does not yield an event in the parent job.


  1. Why doesn't the Start-WPFJob example yield events to the parent job?
  2. Is there some other way to use ShowUI to produce a button in a non-blocking manner and receive events from it?

回答1:


I can't get engineevents to forward properly so far (actually, I can't even get them to do anything, as far as I can tell), I think your best bet is to run the WPFJob, and instead of New-Event, update the $Window UIValue, and then from your main runspace, instead of Wait-Event, use Update-WPFJob in a loop.

I would stick this function into the module (actually, I will add it for the 1.5 release that's in source control but not released yet):

function Add-UIValue {
    param(
        [Parameter(ValueFromPipeline=$true)]
        [Windows.FrameworkElement]    
        $Ui,

        [PSObject]
        $Value
    )
    process {
        if ($psBoundParameters.ContainsKey('Value')) {
            Set-UIValue $UI (@(Get-UIValue $UI -IgnoreChildControls) + @($Value))
        } else {
            Set-UIValue -Ui $ui 
        }        
    }   
}

And then, something like this:

$job = Start-WPFJob {
  Window {
    Grid -Rows "1*", "Auto" {
      New-ListBox -Row 0 -Name LB -Items (Get-ChildItem ~ -dir)
      Button "Send" -Row 1 -On_Click { Add-UIValue $Window $LB.SelectedItem }
    }
  } -SizeToContent "Width" -MinHeight 800
}

Every time you click, would add the selected item to the UI output (if you run that window without the job and click the button a couple of times, then close the window, you'll get two outputs).

Then you can do something like this in the host instead of Wait-Event:

do {
  Update-WPFJob -Job $job -Command { Get-UIValue $Window -IgnoreChildControls } -OutVariable Output
  Start-Sleep -Mil 300
} while (!$Output)


来源:https://stackoverflow.com/questions/27596261/is-there-a-way-to-send-events-to-the-parent-job-when-using-start-wpfjob

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!