質問者
Windowsフォームのコントロール間のイベント発生順序について

質問
-
Windowsフォームのコントロール間のイベント発生順序についてMSDN内で参考となる情報を探してみましたが、
見つけることができなかったので、投稿させていただきます。
たとえば、1つのWindowsフォームに2つのコントロール(textboxとtextbox)があったばあい、
一方のtextboxから、他方のtextboxにマウスでフォーカスが移った場合、
一方のtextboxのLeaveイベントが発生してから、他方のtextboxのEnterイベントが発生すると思うのですが、
これって、どこか(Formクラス内)で制御しているのでしょうか?
もし、参考になる情報など有りましたら教えていただきたいです。
よろしくお願いいたします。
すべての返信
-
バンコランさん、こんにちは。
イベントの順序は意識しないのが鉄則だと思いますが、
今回のようなフォーカス遷移に限っては意識すべき問題かもしれませんね。
バンコラン さんからの引用 Windowsフォームのコントロール間のイベント発生順序についてMSDN内で参考となる情報を探してみましたが、 見つけることができなかったので、投稿させていただきます。
とのことですが、MSDN ライブラリに順序については書いてあると思います。
参考になりますでしょうか? 書かれているとおり、マウスを使うか [Tab] キーを使うかで若干異なります。 -
じゃんぬねっとさん、ありがとうございます。
コントロールEnter, Validatingなどの順序に関しては、以下の情報を参考にさせていただいています。
Windows フォームのイベントの順序
http://msdn2.microsoft.com/ja-jp/library/86faxx0d(VS.80).aspxWindows フォームにおけるマウス イベント
http://msdn2.microsoft.com/ja-jp/library/ms171542(VS.80).aspxやっぱり、イベントの順序は意識しないのが鉄則なんですかねえ。
でも他のイベント、他のコントロールに対する処理順序って記述がないんですよね。
ありがとうございます、もうちょっと探してみます。
-
外池と申します。
非常に悩ましい問題だと思いますが・・・、何の情報にもならないことを恐れず一言申し上げるとすると、
やはり、イベントの順序に依存しないコーディングを実現させることを考えられた方がよいかと思います。
と申しますのも、もしかすると、Debug版とRelease版で、イベントの発生順序が違う「かも」しれません。(別の種類イベントではそういう例を体験したことがあります) また、今後の.Netのバージョンが変わるときに、イベントの発生順序が公然と変わってしまうかもしれません。
特に、今回、問題にされている「順序」は、二つの異なるコントロールの間でのイベントの順序ですので・・・、たぶん、公式なドキュメントって無いじゃないでしょうか・・・。(既に挙げられているMSDNの資料は、いずれも、同一のコントロールで、Focus関係のイベントがどのような順序で発生するかを説明したもので、これは、おそらく、その通りなのだと思います。) ですので、連動させたい(順序をキチっと把握したい)イベントごとにフラグを立てて、イベントの発生順序を把握しつつ動作の順序を制御するような機構をプログラムしてやらないといけないような気もします。
以下、独り言モードですが、識者の方のコメントがあれば、私の後学のためにも嬉しいです。
二つの異なるコントロールのイベントの順序を議論することは、Win32風に言えば、異なるWindowへの異なるMessage送信の順序が定まっているかどうか、ということですよね?
-
外池 さんからの引用 と申しますのも、もしかすると、Debug版とRelease版で、イベントの発生順序が違う「かも」しれません。(別の種類イベントではそういう例を体験したことがあります) また、今後の.Netのバージョンが変わるときに、イベントの発生順序が公然と変わってしまうかもしれません。
初耳です。
デバッグ時のブレークとかそういった自明な問題を除けば、
いままで経験したことがありません。
教えていただけますか?
外池 さんからの引用 二つの異なるコントロールのイベントの順序を議論することは、Win32風に言えば、異なるWindowへの異なるMessage送信の順序が定まっているかどうか、ということですよね?
半ば自明ですが、.NetコントロールのイベントはWin32メッセージに1対1では対応していません。
Enter、GotFocus、Validate辺りのイベントは殆どが.Netによる実装です。
Win32のWindowも、.Netのコントロールも、作成元スレッドのみでしか操作できません。
そのため、異なるWindowでも、同一スレッドで作成されたものであれば、
同じ条件・同じ操作に対しては、いつも同じ順序でメッセージやイベントが発生します。
OSなどの環境と、メッセージやイベントの順序の関係は、
メッセージ、イベント単位でドキュメントをみて確認するしか私は知りません。
追加のメッセージはたくさん出ましたが、
殆どのものが、Win16時代から変わっていません。(もしくは、変わってても気づいていないか。)
イベントドリブンの利点はきちんと享受できてると思います。
WM_PAINTやWM_MOVEなどはWin98辺りでちょっと変わりましたが、それ以降変わっていません。(たぶん)
コモンコントロール系、WM_Notifyのいくつか、は比較的頻繁に変わってるように思えますが、
許容範囲だと思います。
イベントドリブンですので、イベントの意味でコーディングをすべきなのは皆さんの言うとおりだと思います。
殆どの場合、綺麗な方法があります。
-
外池と申します。
Debug版とRelease版でイベントの順序が違っていたのは・・・、すいません、だいぶ前のことなので、よく覚えていないのですが、確か、通信関係のBegin~、End~のような非同期動作をさせて、自作のイベントを発生させるようなアプリだったように記憶しています。イベントごとにログをとりながら動作確認をしていたときに、このような違いに気づいたことがあります。
すいません、ほんと、アヤフヤな記憶なもので。
一方で、
Win32のMessageと、.Netのイベントが1対1で対応しないことは、参考になりました。.Net独自の実装の部分は、今後、順序が変わらないことを期待したいところですが・・・、(数値計算なんかは、あっさり仕様を変えられたりしちゃうので、ちょっと不安です)
-
Win32のWindowも、.Netのコントロールも、作成元スレッドのみでしか操作できません。そのため、異なるWindowでも、同一スレッドで作成されたものであれば、
同じ条件・同じ操作に対しては、いつも同じ順序でメッセージやイベントが発生します。
読み違っているかもしれませんが、Nonqueued Messages もある事ですしそうとも限らないのでは?
更に言えば、SendMessage() で送ったメッセージの方が PostMessage() で送ったメッセージより優先的に処理されませんでしたっけ? SendMessage() 呼び出し元は処理が終わるのを待っているので。でも順序が保証されているのもあります。例えば、他のコントロールに移ろうが何しようがキーボードでタイプした文字はタイプした順序で送られます。入れ替わったらエライ事ですしね。
つまり、メッセージやイベントのカテゴリーの違いで、順序が保証されたりされなかったりするんじゃないかなと思います。
ここでは Leave と Enter の話をしているのでそれを挙げると、これらイベントは同じカテゴリーのはずなので、別のコントロールの Leave が発生してから、更に別のコントロールの Enter が発生するという順序は保証されているんじゃないかなと思います。それを保証しているドキュメントは見たことないですが。イベントの順序は意識しない方が良いという意見もあるようですが、イベントの順序は意識しないといけない場合は意識しないといけません。意識してはいけないのは、イベントに関連付けられているデリゲートの呼び出し順です。
Windows アプリケーションではイベント順序が決まっていたり決まっていなかったりしますが、ASP.NET ではキチッときまっています。
-
囚人 さんからの引用
読み違っているかもしれませんが、Nonqueued Messages もある事ですしそうとも限らないのでは?んーと、
全く持ってミスリーディングな、不正確な文章でした。
「同じ操作・同じ条件」というところを強調したつもりでしたが、
真に同じなら同じになるのが当たり前で、情報量0ですよね。
MOUSEMOVEとかも同じ様におくるよう操作できるとも思えませんし。
極端な話、ランダムなタイミングでランダムなメッセージを送るアプリを作ったら
当然メッセージの順序もランダムになるし。
カテゴリごとに順序がある、というのも語弊がありますよね。
SendMessageを許すなら、どんな順番も有りですから。私の言いたいのは至極当然、自明な話なんです。
メッセージの送信方法にはQueuedとNonQueuedがあります。
Queuedはごく少数の例外を除き、完全なFIFOです。
NonQueuedはその場で同期的に実行します。
(PostMessageはQueuedで、SendMessageはNonQueuedで送ります。)ユーザーによる操作でメッセージがPostされてきた場合を考えます。
メッセージはPostMessageしたり、SendMessageしたりしながら、
Win32ランタイムや.Net、ユーザーコードで処理され、
DefWndProc内で終了処理されます。
NonQueuedで送るというのはWndProcの再起呼び出しですし、
Queuedのメッセージは処理がループに戻るたびに順に処理されますので、
コードからの呼び出し順が同じなら、処理順序も一緒になります。
OSがキューをシャッフルしたり、
SendMessageの自動で変えちゃったりしません。
(自明だよね。)ランタイム内部、.Net、ユーザーコードでは
プログラムの状態に応じて
メッセージを呼んだり、呼ばなかったりしますので、
実際には順番は変わります。
(これも自明。)>Win32風に言えば、異なるWindowへの異なるMessage送信の順序が定まっているかどうか、ということですよね?
そんなわけなので、
たとえ異なるWindowでも、同じスレッドで作られたものなら、
OSの都合とか気分とか天気とかの性で
勝手に順番が変わっちゃうことはありません。
(違うスレッドだったら順序はばらばらというのも当たり前ですねぇ)順番が変わることがあるなら、
それはアプリがそれなりの状態にあったり、
それなりの処理をした結果、順番が変わるのであって、
根拠なく変わっているわけではありません。こんなことが言いたかったのです。
キューはWindowじゃなくてスレッドに付いてるので~
とか考えてたらよくわからない回答になってました。
自明すぎ回答でしたね。
役にもたたないし。長いし。失礼しました。