Skip to content

MS_ASPNETWebFormsEventOrder

nishi_74322014 edited this page Aug 21, 2026 · 1 revision

ASP.NET Web Formsのイベント発生順

概要

ASP.NET Web Forms のイベント発生順について説明する。

補足(なぜ順序が重要か): Web Forms は
ページ ライフサイクルの各段階で「できること」が異なるため、
「動かない」の原因が書いた場所(イベント)の誤りである
ことが非常に多い。

【典型的な失敗】
  ・Page_Load でコントロールの値を書き換えたのに反映されない
      → ViewState / ポストバック データの復元との前後関係を誤っている
  ・Page_Load で毎回データバインドしてしまい、
    ユーザーの入力が消える
      → if (!IsPostBack) の判定漏れ
  ・動的に追加したコントロールが消える
      → Page_Init で作らないと ViewState が復元されない

初期化イベント

  1. コンストラクタ
  2. Page.Init イベント
  3. Page.Load イベント

の順番で動作する。

補足(全体のライフサイクル): 原文が扱う 3 つは冒頭部分で、
実際にはもっと多くの段階がある。実務で押さえるべきものを整理する。

# 段階 この時点でできること
1 コンストラクタ ほぼ何もできない(コントロール未生成)
2 PreInit マスター ページ / テーマの動的切り替え
3 Init 動的コントロールの生成(ここで作らないと ViewState が復元されない)
4 InitComplete
5 ViewState の復元 ← ここで前回の状態が戻る
6 ポストバック データの処理 ← ここでユーザー入力が反映される
7 Load(Page_Load) コントロールの値が確定している。通常の処理はここ
8 コントロール イベント Button.Click 等(後述)
9 LoadComplete
10 PreRender 描画直前の最終調整(表示の書き換えはここ)
11 ViewState の保存
12 Render HTML 生成
13 Unload 後始末(応答は書けない)

要点は 5・6 と 7 の前後関係である。

ViewState 復元(5)→ ポストバック データ(6)→ Page_Load(7)

  → Page_Load の時点では、既にユーザーの入力が
    コントロールに反映されている
  → ここで無条件にデータバインドすると、入力が上書きされる
protected void Page_Load(object sender, EventArgs e)
{
    if (!IsPostBack)          // ← 初回表示時だけ
    {
        BindData();
    }
}

if (!IsPostBack) は Web Forms の基本作法であり、
これを忘れることが最も多い不具合である。

継承時

「親クラス1」 <--- 「親クラス2」 <--- 「派生の末端クラス」と
継承を行っていた場合、

  1. コンストラクタ
    1. 親クラス1 の コンストラクタ
    2. 親クラス2 の コンストラクタ
    3. 派生の末端クラス の コンストラクタ
  2. Page.Init イベント
    1. 親クラス1 の イベント ハンドラ
    2. 親クラス2 の イベント ハンドラ
    3. 派生の末端クラス の イベント ハンドラ
  3. Page.Load イベント
    1. 親クラス1 の イベント ハンドラ
    2. 親クラス2 の イベント ハンドラ
    3. 派生の末端クラス の イベント ハンドラ

の順番で動作する。

移行メモ(誤記): 原文では 2.・3.(Page.Init / Page.Load)の
内訳もすべて「コンストラクタ」と記載されていたが、
文脈からイベント ハンドラの誤記と判断し修正した
(直後の説明「同一のイベントのイベント ハンドラは、
ベースクラスから派生クラスに向けて順番に呼び出される」と整合する)。

  • 基本的に、
    • 同一のイベントのイベント ハンドラは、
      ベースクラスから派生クラスに向けて順番に呼び出される。
    • また、コンストラクタや、Page.Init、Page.Load イベント以外にも様々なイベントがある。
    • 上記以外のイベント種類やイベント発生順については、
      ASP.NET のマニュアルを参照のこと。

補足(なぜ基底クラスから呼ばれるのか): これは
AutoEventWireup による自動結線の仕組みによる。

AutoEventWireup="true"(既定)
  → Page_Init / Page_Load という「名前」のメソッドが
    自動的にイベント ハンドラとして登録される
  → 基底クラスの分から順に登録される
  → デリゲートは登録順に呼ばれる
      = 基底クラス → 派生クラス

**override ではなく「イベント ハンドラの多重登録」**である点が要点で、
派生側で基底側の処理を打ち消すことはできない(両方走る)。

// 基底側の処理を制御したい場合は、override にする
protected override void OnLoad(EventArgs e)
{
    // 基底の処理より前に何かする
    base.OnLoad(e);      // ← 呼ばないと Load イベント自体が発火しない
    // 基底の処理より後に何かする
}

フレームワークの基底ページ クラスを作る場合は、
Page_Load ではなく OnLoadoverride する方が
呼び出し順を制御できて確実である。

コントロール イベント

初期化イベントの次に、コントロール イベントが発生する。

AutoPostBack = true

PostBack につき、1イベントしか発生しない。

AutoPostBack = false

  • PostBack につき、複数イベントが発生し得る。
  • 例えば、Button.Click + TextBox.TextChanged

補足(複数イベント時の順序): 原文が指摘する
「複数イベントが発生し得る」場合の順序も、実務では重要になる。

① 変更通知イベント(Changed 系)
     TextBox.TextChanged、DropDownList.SelectedIndexChanged、
     CheckBox.CheckedChanged …
     → コントロールの宣言順(ページ上の並び順)で発火

② ポストバックを引き起こしたイベント(1 つだけ)
     Button.Click、LinkButton.Click …

つまり、「Click より先に TextChanged が走る」

テキストを書き換えてから[保存]ボタンを押した場合
  TextChanged → Click の順
  → TextChanged 側で何か副作用を起こすと、
    Click 側の前提が変わっている、という事故が起きる

AutoPostBack の意味の整理:

設定 挙動
AutoPostBack="true" そのコントロールを変更した瞬間にポストバックする
onchange で JavaScript が __doPostBack を呼ぶ)
AutoPostBack="false"(既定) 変更してもポストバックしない
次にボタン等でポストバックした時に、まとめて発火する

AutoPostBack="true" を多用すると、
入力のたびに全体がポストバックされて重くなる
ため、
連動する必要がある箇所に限って使うのが定石である。

なお、これらの挙動はすべて ViewState と __doPostBack
依存しており、部分描画とJavaScript
述べられる UpdatePanel の複雑さの根にもなっている。

参考

Microsoft Learn


Tags: 移行, .NET開発, ASP.NET, ASP.NET Web Forms

NetDevInfraWiki

マイクロソフト系技術情報 Wiki
Open 棟梁 Wiki

(未着手)

開発基盤部会 Wiki

移行管理: DONETODO

Clone this wiki locally