読者です 読者をやめる 読者になる 読者になる

qshinoの日記

Powershell関係と徒然なこと

WPF ShowDialog()中の非同期イベント

ShowDialog()中に非同期イベントを処理できない。

PowershellWPFのShowDialog()を処理中に非同期イベントが発生しても処理されない件、原因不明ながら回避策にて対応。

なお、イベントの発生と処理は別物。発生時刻をイベントのプロパティTimeGeneratedで確認。処理時刻をハンドラでの(Get-Date)で確認する。

まずは問題

$win = xxx でWindow生成 $win.ShowDialog()

UI内のイベントで Start-Process のExited EventをRegister-ObjectEventで登録。これはUIスレッドで発生しないため、非同期イベント。

プロセスが終了してもUIスレッドで処理されない。

但し、UIスレッド内でGet-Eventした時に前記イベント発生。

イベントの生成時刻プロパティを見ると、UIスレッドで処理された時刻よりかなり前に発生していた。

  • 対策1 UIのボタンなどの処理で、Get-Eventする。
  • 対策2 DispatcherTimerで定期的にイベント処理を発生させる。

対策1

単純にボタンでGet-Event。ボタン名が"kita", Windowが$winとすると、

$kita = $win.FindName("kita")
$kita.add_click( {Get-Event})

kitaボタンを押すと、非同期イベントがあれば処理してくれる。

対策2

タイマーイベントの副作用で、非同期イベントを処理。ある意味、前記のkitaボタンをタイマーが自動で押してくれる様なもの。

$proc = Start-Process cmd -Passthru

$timer = New-Object System.Windows.Threading.DispatcherTimer
$timer.interval = New-Object TimeSpan(0,0,1)
$timer.add_tick({
  Write-Host "tick" 
  if ( $this.tag ){
    # イベント発生済み
    # イベントジョブ削除
    $this.Stop()
    Remove-Job -id ($this.tag).id
    $this.tag = $null
})
$timer.IsEnabled = $true
$timer.Start()
$timer.tag = $null

$ev = Register-ObjectEvent $proc -EventName Exited -Messagedata @{timer=$timer;ev=$ev;dispatcher=[System.Windows.Threading.Dispatcher]::CurrentDispatcher } $timer -Action { 
  $data = $event.MessageData
  $timer = $data.timer
  $timer.tag = $data.ev
  Unregister-Event -SourceIdentifier $EventSubscriber.Name
  # 何らかの後処理。
  # 本処理PSEventJobがJobとして残っているので、どこかで削除する必要あり。
  # UIスレッド処理: $eventは引数
  $data.dispatcher.BeginInvoke({
    # uiスレッド処理
  }, @($event))
}

参考

http://d.hatena.ne.jp/omoisan/touch/20090711/1249783732

http://main.tinyjoker.net/Tech/CSharp/WPF/�̥����åɤ������Ǥ������.html

http://www.atmarkit.co.jp/ait/spv/1411/04/news133.html

http://ari-it.doorblog.jp/archives/30059088.html

Dispatcher class

https://msdn.microsoft.com/ja-jp/library/system.windows.threading.dispatcher(v=vs.110).aspx#メソッド

Peocess Exited event

https://msdn.microsoft.com/ja-jp/library/system.diagnostics.process.exited(v=vs.90).aspx

WPF timer使用例

https://code.msdn.microsoft.com/windowsdesktop/XAMLCVB-WPF-Windows-WPF-2aab6085

DispatcherTimer

https://msdn.microsoft.com/ja-jp/library/ms615945.aspx#継承階層

IsEnabled

https://msdn.microsoft.com/ja-jp/library/system.windows.threading.dispatchertimer.isenabled.aspx

tag property

https://msdn.microsoft.com/ja-jp/library/system.windows.threading.dispatchertimer.tag.aspx

TimeSpan

https://msdn.microsoft.com/ja-jp/library/system.timespan(v=vs.110).aspx

コンストラクター

https://msdn.microsoft.com/ja-jp/library/bk8a3558(v=vs.110).aspx