Repeaterのコントロールツリー復元機能
はじめに
ASP.NETでの開発効率を上げるために、使いこなすことが非常に重要なコントロールのひとつにRepeaterコントロール(以降、単に「Repeater」と呼ぶ)がある。本エントリでは、Repeaterのコントロールツリー復元機能について述べる。
なお、本エントリの内容は、おそらくドキュメント化されておらず、私が独自に調査した結果に基づく。
コントロールツリー復元機能とは?
Repeaterには、ViewStateからのコントロールツリーの復元機能がある。どういうことかというと、RepeaterでViewStateが「本当に」有効になっている場合、Repeaterへのデータバインドを一度行えば、ViewStateが保存される期間の間*1は、再度データバインドを行わなくても、Repeater以下のコントロールツリーが復元されるということだ。
仕組み
Repeaterは、どのようにしてコントロールツリーを復元しているのか、その仕組みを説明する。
まずは
そのためにはまず、ViewStateの仕組みが理解できていなければならない。本ブログのエントリ「ViewStateによるコントロールのプロパティ値復元の仕組み」を参照されたい。
RepeaterがViewStateに保存する値
Repeaterは、データバインドされると、その項目数(Items.Count)をViewStateに保存する。このことによりRepeaterは、一度データバインドされた後は、データバインドされた際のデータ項目数を、再度データバインドすることなく知ることができる。
Itemsプロパティのgetterでの処理
RepeaterのItemsプロパティのgetterでは、上記で保存した項目数を基に、項目の復元処理が行われる。その際に活用されるのが、テンプレート機能だ。
テンプレート機能とは
Repeaterを使用する場合、以下のようなコードを記述すると思う。
<asp:Repeater ID="rpt" runat="server"> <ItemTemplate> <asp:Label ID="lbl" runat="server" Text="<%# Container.ItemIndex %>" /> </ItemTemplate> </asp:Repeater>
このItemTemplateタグで囲まれた範囲がテンプレートだ。テンプレートのプロパティを公開しているコントロール(ここではRepeater)では、その内部のコントロールツリーを、いつでも、いくつでも生成することができる。
項目の復元処理
Repeaterは、以下の2つを組み合わせることで、項目を復元することができる。
- ViewStateに保存しておいた項目数
- テンプレート機能
ただし、ここまでで復元できるのは、コントロールツリーと、aspxのタグ内で設定されたプロパティ値までであり、プログラムで変更されたプロパティ値が復元できない。
プログラムで変更されたプロパティ値の復元
プログラムで変更されたプロパティ値の復元は、静的コントロールと同様、ViewStateからのプロパティ値復元機能で行われる。Repeaterは、テンプレート機能によって前回のHTTPレスポンス処理時と全く同じコントロールツリーを復元できるので、Repeater内に配置した各コントロールに、その各コントロールのViewStateを渡すことができる(その処理はRepeater独自のものでなく、Controlで定義されている)。そして、Repeater内に配置した各コントロールのプロパティ値が、ViewStateから復元される。
Repeaterが行っているのは、あくまで各コントロールのViewStateを渡すところまでであることに注意する。渡したViewStateがどう処理されるかを、Repeaterは知らない。
復元できる場合とできない場合
基本的には上記のとおり、一度Repeaterにデータバインドしてしまえば、次回以降のポストバックではコントロールツリーとそのプロパティ値までが完全に復元される。しかし以下のような場合、例外的に復元できない。
- RepeaterのViewStateが有効でない
- テンプレート内に動的に追加されたコントロール
RepeaterのViewStateが有効でない
上記の仕組みを理解していれば当然であることがわかるが、RepeaterのViewStateが有効でない場合は復元できない。Repeaterが項目数をViewStateに保存することができないからだ。
なお、ここでの「有効でない」は、EnableViewStateでなくIsViewStateEnabledの方の意味であることに注意する。
Repeater内のコントロールでのイベントとの関係
コントロールツリーの復元機能は、Repeater内に配置したコントロールで発生するイベントにも深く関係する。
ASP.NETのイベント処理の詳細については別途説明したいと思っているが、イベントが正常に発生するためには、前回のHTTPレスポンス処理時とコントロールツリー(正確にはUniqueID)が一致する必要がある。よって、Repeaterにコントロールツリー復元機能がないと、Repeater内に配置したコントロールでイベントが発生しなくなってしまう。このことをこれまでの話と考え合わせると、以下のとおりにしなければ、Repeater内に配置したコントロールでイベントが正常に発生するようにするのが、非常に難しいことがわかる。
ただ、難しいのは確かだが不可能ではない。どうすれば良いのかというと、ページのLoadイベントまでの間に、コントロールツリーを完全に復元すれば良い。イベントを発生させる処理は、ページのLoadイベント完了後に行われるためだ。そこで、上記のとおりにしない場合の代替案を挙げる。
ViewStateが無効なRepeaterでは
前回のHTTPレスポンス処理時にRepeaterにバインドしたデータソースを、SessionなりViewStateなりに保存しておき、ページのLoadイベントまでの間にRepeaterにデータバインドする。ただし、ViewStateに保存しておくくらいであれば、RepeaterのViewStateを有効にした方が良いだろう。これに対し、Sessionに保存すればRepeaterのViewState分の通信量が削減できる。インターネットサイトなど、できるだけ通信量を削減したい場合で、サーバリソースが潤沢なのであれば、この方法が良いかもしれない。
GridViewなどではどうか
本エントリではRepeaterを例にとったが、GridViewなどRepeater以外のデータ バインド Web サーバー コントロールでも概ね同じだと思われる。
*1:ポストバックが連続している間