はじめに
前回は、ITemplateを用いてカスタムコントロールのプレゼンテーションをaspxに分離する方法を解説しました。
しかし、前回までの解説では、プレゼンテーションに必要な値をすべてaspx内に記述することが前提となっています。これでは部分的に変わるコントロールの値をすべてコントロール側で実装する必要があり、ビューにかかわる知識を寄り多くコードに入れ込む必要があります。つまり、このままだと、プレゼンテーションとロジックを分離するという基本的な方針と合いません。
今回は、逆にaspx内からコントロールのデータを参照する方法を解説します。
対象読者
ASP.NETにおけるカスタムコントロールの作成を十分に理解し、前回の記事を読んでいて、Repeater
などのコントロールでデータ連結式を用いたことがある方。
必要な環境
Microsoft Visual Web Developer 2005で確認しています。ASP.NET 1.0以降の環境なら配置の変更だけで対応できるはずです。
変更前のソリューションの説明
Weather
は、次のように天気予報を表示するWebControlです。
Weather
コントロールは、WeatherDataSouce
から与えられる天気情報を元に、天気予報を表示します。WeatherDataSource
はただのダミー実装で、ここでの解説の主体ではありません。
以後、本稿ではWeather
コントロールを変更していき、ロジックとプレゼンテーションの分離をしていきます。
さっそく、変更前のWeather
コントロールを見てみましょう。
<div> <MU:Weather runat="server" /> </div>
protected override void CreateChildControls() { Label day; Label weather; foreach (WeatherDataItem item in _dataSource.Weathers) { day = new Label(); day.Text = item.Date.ToString("yyyy/MM/dd"); weather = new Label(); switch (item.Type) { case WeatherType.Sunney: weather.Text = "晴れ!"; break; case WeatherType.Cloudy: weather.Text = "曇り!"; break; case WeatherType.Rainy: weather.Text = "雨!"; break; } Controls.Add(day); Controls.Add(new LiteralControl("<br>")); Controls.Add(weather); Controls.Add(new LiteralControl("<br><hr>")); } }
見て分かる通り、与えられたデータを元に日付と天気を表示しています。このコードには前回と同様、プレゼンテーションの部分とロジックがCreateChildControls
にすべて入ってしまっている、という問題があります。
目標とするaspx
理想は、前に挙げたWeatherコントロールの表示に係わる所を、次のようにaspxに分離すべきでしょう。
<div> <MU:Weather runat="server"> <Template> (日付)<br> (天気)<br><hr> </Template> </MU:Weather> </div>
ここで問題があります。上記、「(日付)」の部分と「(天気)」の部分をどうaspxで記述したら良いのでしょうか? この値は、WeatherDataSource
からくる値です。
結論から言うと、テンプレート内でデータを展開する手段がASP.NETでは用意されていて、それを使うことになります。その手段が、実は皆さんが普段使っているデータ連結式、つまり<%#
で始まり%>
で終わる文です。それを用いると、次のような記述になります。
<div> <MU:Weather runat="server"> <Template> <%# Container.FormatedDate %><br> <%# Container.FormatedWeatherType %><br><hr> </Template> </MU:Weather> </div>
これはASP.NETでよく見られる、Repeater
コントロールと同じ物です。
以下、これを実現するためのデータ連結式を解説してきます。
テンプレート化
ここでは、以下に示すようなコントロールツリーになるように、コーディングを進めます。
この各WeatherDayContainer
がちょうど前回のCheckText
に相当します。
それでは前回のコードを参考に、このツリーを作ってみましょう。まずはWeatherDayContainer
を作ります。
public class WeatherDayContainer : WebControl, INamingContainer { }
これはテンプレートが下に展開されるだけのコントロールなので、中身は殻にしておきます。INamingContainer
については、後ほど解説します。
次に前回の記事にならい、ITemplateを受け取る部分を作ります。
private ITemplate _dayTemplate; [TemplateContainer(typeof(WeatherDayContainer))] public ITemplate DayTemplate { set { _dayTemplate = value; } }
これで_dayTemplate
にITemplateがセットされるのは前回解説しました。最後にCreateChildControls
で、これを使うように変更します。
protected override void CreateChildControls() { foreach (WeatherDataItem item in _dataSource.Weathers) { WeatherDayContainer container = new WeatherDayContainer(); _dayTemplate.InstantiateIn(container); Controls.Add(container); } }
あとは、aspx側にテンプレートを記述します。
ここでは、前回までの知識で分かるようにデータ連結式は使わず、暫定的にいつも同じテキストを表示するようにします。
<MU:Weather runat="server"> <DayTemplate> 毎日晴れ<br /> </DayTemplate> </MU:Weather>
これにより、「毎日晴れ」が4回表示されます。