フォームのイベント実験 への返答

投稿で使用できる特殊コードの説明。(別タブで開きます。)
本名は入力しないようにしましょう。
投稿した後で削除するときに使うパスワードです。返答があった後は削除できません。
返答する人が目安にします。相手が小学生か社会人かで返答の仕方も変わります。
最初の投稿が質問の場合、質問者が解決時にチェックしてください。(以降も追加書き込み・返信は可能です。)
※「過去ログ」について書くときはその過去ログのURLも書いてください。

以下の返答は逆順(新しい順)に並んでいます。

投稿者 Suzuran  (社会人) 投稿日時 2013/5/7 15:57:55
すみません。
僕は「MessageBox.Show」でやっていました。
結果が変わる事を知りませんでした。
投稿者 YuO  (社会人) 投稿日時 2013/5/7 02:25:29
VisibleChanged内で
・MessageBox APIを実行
・Formを作ってShowDialog(Me)を実行
のどちらでもShownがOnVisibleChanged終了より前に動く,ということから,APIレベル,DialogBox系APIの内部動作が関係していそうです。

VisibleChangedに入った後から,OnShownまでにWndProcメソッドで捕らえたメッセージは以下の通りです。
・WM_CANCELMODE
・WM_ENABLE (wParam = 0)
・WM_WINDOWPOSCHANGING (flags = &h0037 : SWP_DRAWFRAME Or SWP_NOACTIVATE Or SWP_NOZORDER Or SWP_NOMOVE Or SWP_NOSIZE)
・WM_ACTIVATEAPP (wParam = 1, lParam = 1)
・WM_DWMNCRENDERINGCHANGED (wParam = 1)
・unknwon (&hC1E4, RegisterWindowMessage)
直接的には最後のuMsgが&hC1E4の時にShownが呼び出されるようですが,
これ自体はRegisterWindowMessage APIで登録された値であると思われるため,
これをAPIがSendしているとは考えられず,この値をSendMessageしているコードがあると思われます。

また,それ以外のメッセージを投げてもOnShownは呼ばれませんでした。
.NETのソースコードを解析していけば,なぜShownが呼ばれるかが見つかるかもしれませんが,そこまでは解析していません。
投稿者 るきお  (社会人) 投稿日時 2013/5/6 20:24:35
確かに
Load→VisibleChanged→Shown
が正確ですね。
Debug.WriteLineを各イベントにしかけると確認できます。

しかし、MsgBoxを使うとちょっとおもしろい結果になります。

Form1側
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
    Dim f As New Form2
    f.Show()
End Sub


Form2側
Public Class Form2

    Private Sub Form2_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Debug.WriteLine("Load")
        MsgBox("Load")
    End Sub

    Private Sub Form2_Shown(sender As Object, e As EventArgs) Handles Me.Shown
        Debug.WriteLine("Shown")
        MsgBox("Shown")
    End Sub

    Private Sub Form2_VisibleChanged(sender As Object, e As EventArgs) Handles Me.VisibleChanged
        Debug.WriteLine("VisibleChanged")
        MsgBox("VisibleChanged")
    End Sub
End Class


これを実行するとMsgBoxは次の順番に表示されます。
Load→Shown→VisibleChanged
一方、出力ウィンドウ(デバッグ)には次のように表示されます。
Load→VisibleChanged→Shown
だから、適切な方法で確認しないとMSDNに記載されている順番と一致した結果になりません。

このように順番が変化する理由は追及していませんが、
多分、フォームが表示されていないのにメッセージボックスだけ表示するようなプログラムになっているので、.NET Frameworkがつじつまを合わせるために中でトリッキーな動きをしているのだと思います。
投稿者 YuO  (社会人) 投稿日時 2013/5/6 19:26:14
ShownとVisibleChangedのイベントの発生順序が,MSDNやこちらでのテスト(.NET 4.5 on Win8)と異なるのですが。

Windows フォームのイベントの順序
http://msdn.microsoft.com/ja-jp/library/86faxx0d.aspx

本当に,Load→Shown→VisibleChangedの順で発生したのですか。
投稿者 るきお  (社会人) 投稿日時 2013/5/6 18:51:57
Loadは表示前、Shownは表示後という使い分けをします。
最近のVBやC#はLoadイベント内で発生した例外をデバッグできないというバグがあるのでLoadイベントがちょっと使いにくいです。
このせいで私は軽い処理ならLoadではなく、Shownに書くようになってしまいました。

VisibleChangedはHideメソッドや、Visibleプロパティなどでフォームを非表示にしたり、再表示したりということをすると単体でも発生します。

投稿者 Suzuran  (社会人) 投稿日時 2013/5/6 10:44:38
フォームコントロールには、Load, Shown, VisibleChanged, 似ているイベントが3つあります。
僕は、この3つのイベントが起きる順番を調べてみました。

<順番>
1.Load
2.Shown
3.VisibleChanged

このようになりました。