10

add_NameOfEvent({scriptblock})PowerShell では、オブジェクトの - メソッドを使用してイベントをサブスクライブできます。これは、ボタンなどの Form オブジェクトではうまく機能しますが、 a で試してみるとうまくいきSystem.Timers.Timerませんでした。何故ですか?サンプル:

$timer1 = New-Object System.Timers.Timer
$timer1.Interval = 2000
$timer1.add_Elapsed({ Write-Host "Timer1 tick" })

$timer2 = New-Object System.Timers.Timer
$timer2.Interval = 2000
Register-ObjectEvent -InputObject $timer2 -EventName Elapsed -Action { Write-Host "Timer2 tick" }

$timer1.Start()
$timer2.Start()

$timer2正常に動作します$timer1が、コンソールに書き込むことはありません。Timer元との違いは何ですか。フォームコンポーネント(add_...メソッドが機能する場所)? Timer別のスレッドで実行され、そのために「非表示の」コンソールに書き込みますか?

メソッドに慣れていない人のために、メソッドがフォームコンポーネントで機能することの証明:

PS > Add-Type -AssemblyName System.Windows.Forms
PS > $b = New-Object System.Windows.Forms.Button
PS > $b.add_click({ Write-Host "button" })
#Get-EventSubscriber won't show this event, but it's added
PS > $b.PerformClick()
button
4

2 に答える 2

7

このコードを試すと:

$w = new-object 'System.Windows.Forms.Form'
$timer1 = New-Object System.Timers.Timer
$timer1.Interval = 2000
$timer1.add_Elapsed({ Write-Host "Timer1 tick" })
$timer1.SynchronizingObject = $w
$timer1.Start()
$w.ShowDialog()

System.Timers.Timer は (ac# コードのように) ウィンドウ フォームと同期できるため、期待どおりの動作が見られます。

ISynchronizeInvokePowerShell コンソールの問題は、タイマーが別のスレッドで作成され、間隔が経過したときに発行されるイベント ハンドラー呼び出しをマーシャリングするために使用されるオブジェクトを表すインターフェイスを公開しないため、コンソールと同期できないことです。 .

SynchronizingObjectisの場合null、Elapsed イベントを処理するメソッドがシステム スレッド プールのスレッドで呼び出されます。

IMO 舞台裏の Register-ObjectEvent は、システム スレッド プールを作成して、イベント ハンドラー呼び出しを実行します。

何をするかを手で再作成することはできませんがRegister-ObjectEvent 、いくつかの c#/Pinvoke コードで可能だと思います。

于 2013-03-26T10:06:41.817 に答える
1

この記事では、PowerShell エンジンでイベントを発生させるには、イベントをサブスクライブする必要があることを示しています。私は自分のセッションで$timer2.開始しようとしていましたが、公開されているメソッドを使用して動作していないようです。具体的には.$timer1.Start()

于 2013-03-19T17:43:49.210 に答える