日記
.netメモ「ascxコントロールをページから制御」Edit

ascxコントロールは、Webコントロール(カスタムWebコントロール)などの部品群とは似ているようで違う。Pageletという別名がその実体をかなり正確に表現している。

Webコントロールは独立したオブジェクト(部品)としてきちんと扱える。ページ上に配置することで、ページ上のコード(コードビハインド)からWebコントロールに直接アクセスすることができる。

しかし、ascxコントロールは一見独立したオブジェクトのようにみえるが、その実質は親ページの一部として組み込まれるincludeファイルのようなものだ。だからWebコントロールのように、親ページからascxコントロール(のオブジェクトポインタ)は見えない(自分で宣言文を書いてもダメ)。

しかし、コードからascxコントロールのプロパティを設定できないのでは困るので、いろいろ試してみたところ、Pageのコードとして、

CType(FindControl("Form1").FindControl(コントロールのID),コントロールの型)

と表現することで、ascxコントロールにアクセスできることがわかった。かなり面倒くさい(というか醜い)表記だが、これでascxコントロールのプロパティやメソッドを呼ぶことができる。

しかし、ほかにも問題がある。それはイベントハンドラの実行順の問題だ。ascxコントロール内に記述するPage_Loadなどのイベントは、ascxコントロールのLoadイベントというよりは、親ページのPage_Loadの一部のようなものだ。たとえばPage上にascxコントロールCtrlA、ascxコントロールCtrlBの二つをおいた場合、各標準イベントハンドラが呼ばれる順番は、

  • CtrlA_Init
  • CtrlB_Init
  • Page_Init
  • Page_InitializeComponent
  • Page_Load
  • CtrlA_Load
  • CtrlB_Load

という順番になる。ページ内にある複数のascxコントロールの同じイベント(たとえばPage_Load)が発生する順番は、Page(aspx)内に記述されたascxコントロール(<uc1:〜>)の順番通りになっているようだ(特に保証はないが、試してみた限りではそうなっている)。

ここで問題なのは、Initはascxコントロールの方が先なのにもかかわらず、LoadはPageの方が先になっている点だ。Page_Loadでコントロールのプロパティを設定したとしても、その後のCtrl_Loadにプロパティ初期化コードを書いてしまうと、Pageからのプロパティ設定は無効になってしまう。そのような使い方の場合、ascxコントロール内でのプロパティ初期化処理は、Ctrl_Initの方で実行しなければならない。

しかし、その逆の使い方をしたい場合もある。ascx側で親ページのPage_Load処理の結果によって、自分自身の初期化処理を変えたい場合だ。その場合は、Page_Loadのあとに呼び出されるCtrl_Loadでascxコントロールの初期化処理を行う必要がある。

つまり、ascxコントロールおよびPageにおける初期化処理は、その初期化処理の結果が相互にどのように関係するかを考えつつ、適切な実行順序になるよう記述するイベントハンドラを割り振らなければならないことになる。

具体的にいうと、ascxコントロールの初期化処理において、その結果がPageに影響を与えるような内容はCtrl_Initに記述し、逆にPageから影響を受けるような初期化処理はCtrl_Loadに記述すればいいことになる。Page側のイベント実行順序は、Page_LoadもPage_InitもCtrl_InitとCtrl_Loadに挟まれているので、ascxコントロール側の記述場所さえ守ればどちらに書いてもかまわない。

※現象に関する記述はあっているはずだけど、現象の理解(解釈)に関する記述は間違っている可能性が高い。と一応補足しておく。

Published At2002-05-21 00:00Updated At2002-05-21 00:00