2013-03-19 20 views
10

PowerShellでは、オブジェクトのadd_NameOfEvent({scriptblock})メソッドを使用してイベントを購読することができます。これはボタンなどのフォームオブジェクトではうまくいきますが、System.Timers.Timerで試してみるとうまくいきませんでした。何故ですか?サンプル:add_EventNameが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をexと異なるものにする理由フォームコンポーネント(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 

答えて

6

あなたはこのコードをしようとした場合:

$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は(C#のコードのように)窓の形で同期することができますので、あなたが予想される動作が表示されます。

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

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

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

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

+0

+1。私は尋ねる前にsynchronizingobjectについて読んだことがあります。また、フォームにコントロールを追加するために使用できる通常の追加コントロールメソッドもsyncronizingobjectプロパティを設定していると思います。しかし、コンソールとタイマーを同期させるために使用できる変数/オブジェクトが必要です。私はこれを正解と見なしますが、ダミーフォームを作成せずに誰かが完全な解答を提供できる場合に備えて、数日待つでしょう:-) –

+0

Graimer私は@ x0nがより良いものを与えることを願う、彼はパワーシェルイベントに関する深い知識を持っています。とにかく私は本当に面白いあなたの質問を見つけた! –

1

This articleは、あなたがそれらをPowerShellのエンジンで提起するためのイベントをサブスクライブする必要があることを私に示しています。 $timer2.自分のセッションで$timer1を開始しようとしていて、公開されているメソッドを使用して動作していないと思われる場合は、具体的に.Start()を参照しています。

+0

私はイベントに登録する必要があることを知っていますが、それは 'add_eventname'がショートカットであることです。 「スクリプトブロックで.NETイベントを直接処理するには、そのオブジェクトのAdd_Event()メソッドを呼び出す」ソース:http://www.pavleck.net/powershell-cookbook/ch31.html。前述したように、このショートカットは.netフォームコンポーネントと連動するので、.netタイマーとはどのような違いがありますか? :S –

+0

このメソッドはフォーム固有のものかもしれませんが、Get-Member -ForceコマンドレットでPowerShellに公開されている理由がわかりません。 しかし、add_event()はget-memberにforce paramを使用しないでpowershellに公開されていないので、これは意図的かもしれないと感じています。あなたがリンクしているソースでも、Add_Event()の使用について言及していますが、実際にはそれを使用することはありません。代わりに、著者はイベントを登録します。このドキュメントは、Timerクラスにadd_event()メソッドがないことを示しています。 http://msdn.microsoft.com/en-us/library/system.timers.timer_methods.aspx –

+0

'add_eventname'は、PSが処理する「非表示/動的」メソッドです。どのオブジェクトにも表示されません。 '$ timer1.add_Elapsed'と入力すると、それが存在するという証明として過負荷状態になります。 –

関連する問題