2009年06月11日
川俣晶の縁側ソフトウェア技術雑記 total 16271 count

.NET FrameworkのWindowsフォームではLoadイベントより前にResizeイベントが発生することがある

Written By: 川俣 晶連絡先

 かなり悩ましい問題に遭遇したのでメモ。

前提条件 §

  • 画面サイズ(ピクセル数)よりも大きなサイズのウィンドウを作成させる
  • このとき、ウィンドウの存在を通知するメッセージ(イベント)がウィンドウ側に発生する (A)
  • システムはウィンドウのサイズを画面サイズに収まるように補正する
  • このとき、サイズ変更のメッセージ(イベント)がウィンドウ側に発生する (B)

 ここで、(A)と(B)はどちらが先に到着するか。

Win32ネイティブの場合 §

 (A)はWM_CREATE、(B)はWM_SIZEとすると、(A)→(B)の順になる。

VB6の場合 §

 (A)はLoadイベント、(B)はResizeイベントとすると、(A)→(B)の順になる。

C# 3.5/VB2008の場合 §

 (A)はLoadイベント、(B)はResizeイベントとすると、(B)→(B)→(A)の順になる。

検証アプリの一例 (VB2008) §

 Windowsフォームのプロジェクト作成後に2つのイベントとコンストラクタを作成。

Public Class Form1

    Public Sub New()

        ' この呼び出しは、Windows フォーム デザイナで必要です。

        InitializeComponent()

        ' InitializeComponent() 呼び出しの後で初期化を追加します。

        Me.Width = 10000

        Me.Height = 10000

    End Sub

    Private Sub Form1_Load(ByVal sender As System.Object, 

ByVal e As System.EventArgs) Handles MyBase.Load

        System.Diagnostics.Trace.WriteLine("Load called")

    End Sub

    Private Sub Form1_Resize(ByVal sender As System.Object, 

ByVal e As System.EventArgs) Handles MyBase.Resize

        System.Diagnostics.Trace.WriteLine("Resize called")

    End Sub

End Class

問題は何か §

  • 単純なメッセージ/イベントの対応関係を取った書き換えでは上手く動かない可能性がある。特にVB6からの書き換えでは、名前が同じであるので同じ挙動と漠然と思い込んでしまう可能性があり、危険
  • ウィンドウの指定された初期サイズよりも画面サイズが小さい場合にのみ発生するので、問題が顕在化しにくい。画面の大きい開発マシンでは起らないが、画面を最小サイズにした実機でのみ起る等
  • 画面解像度800x480のような小画面を持つネットブックが流行りものとして出現した結果、フォームサイズ800x600ぐらいで作成されたソフトで突然問題が顕在化することがあり得る (これまでは、800x600より小さな画面はほとんどあり得なかったので顕在化しなかった可能性があり得る)
  • 古くからやっていて知識経験が多いと、挙動を見誤っていることになかなか気づけない可能性がある

感想 §

 他にもいろいろ思うところはありますが、突っ込んでいる時間がないので以上のメモのみ。あまり突っ込んでいないので、正しくない可能性あり。ちなみに、私の現状は上記問題の3番目と4番目に当てはまっています。気づくまで要した時間はそれほど長くはありませんが。