ASP.NET 2.0 の GridView の例: TemplateFields の操作
ここをクリックして TOC に戻ります。
GridView を使用すると、さまざまな種類の列を使用できます。その中で、これまでに 2 つの列を見てきました。
- 指定した DataSource フィールドの値をテキストとして表示する BoundField。 (これは、Smart Tag インターフェイスを介して GridView を DataSource に関連付けるときに既定で使用される列の種類です)。
- 指定した DataSource フィールドのイメージ パスに基づいてイメージを表示する ImageField。 (前の演習では、この列の種類を使用する例を見ました。
もう 1 つの便利な列の種類は TemplateField です。これにより、HTML マークアップ、Web コントロール、およびデータ バインディング構文を組み合わせることができます。 (ASP.NET 1.x DataGrid に精通している場合、TemplateFields は DataGrid の TemplateColumn と同じになります)。TemplateField の一般的な用途の 1 つは、出力をマッサージするカスタム ロジックを実行することです。もう 1 つの一般的な用途は、 GridView 列内に他の Web コントロールを埋め込むことです。 両方の例を見てみましょう。
カスタム ロジックを使用した出力の変更
たとえば、Northwind データベースの Employees テーブルには、 HireDate というフィールドが含まれています。 HireDate フィールドを表示するのではなく、雇用された日数に基づいて年功序列レベルを表示する必要があったとします。 従業員が 1,000 日以内に雇用されていた場合、"初心者" というラベルが付きます。1,000日から4,000日の間に雇用されていた場合、彼らは「アソシエイト」というラベルが付けられます。4,000日から8,000日の間に働いていた人は「常連の一人」とラベル付けされ、8,000日を超える従業員は「An Ol'Fogey」というラベルを獲得していました。
これを実現するには、このロジックを実行し、適切な年位レベルを含む文字列を返す ASP.NET ページでメソッドを呼び出した TemplateField を使用できます。 最初の手順では、 GridView に TemplateField を追加します。これは、 GridView のスマート タグの [列の編集] オプションを使用して実行できます。 TemplateField が追加されたら、HTML ビューに戻り、TemplateField の ItemTemplate> を作成<します。 この <ItemTemplate> では、書き込み先のメソッド ComputeSeniorityLevel(numberOfDaysEmployed) を呼び出します。これにより、有効な年位レベルのいずれかを含む文字列が返されます。 TemplateField からメソッドを呼び出すための構文は次のとおりです。
<%# FunctionName(parameter1, parameter2, ..., parameterN) %>
したがって、 構文で メソッドを呼び出すと、次のようになります。
' Visual Basic... <%#ComputeSeniorityLevel(DateTime.Now - CType(Eval("HireDate"), DateTime))%> // C#... <%# ComputeSeniorityLevel(DateTime.Now - (DateTime)Eval("HireDate")) %>
DataSource フィールドの 1 つから値にアクセスするには、Eval(fieldName) メソッドを使用します。
この追加により、 GridView の宣言構文は次のようになります。
<asp:GridView ID="GridView1" Runat="server" DataSourceID="employeeDataSource" AutoGenerateColumns="False" BorderWidth="1px" BackColor="White" GridLines="Vertical" CellPadding="4" BorderStyle="None" BorderColor="#DEDFDE" ForeColor="Black"> <FooterStyle BackColor="#CCCC99"></FooterStyle> <PagerStyle ForeColor="Black" HorizontalAlign="Right" BackColor="#F7F7DE"></PagerStyle> <HeaderStyle ForeColor="White" Font-Bold="True" BackColor="#6B696B"></HeaderStyle> <AlternatingRowStyle BackColor="White"></AlternatingRowStyle> <Columns> <asp:BoundField HeaderText="Last" DataField="LastName" SortExpression="LastName"></asp:BoundField> <asp:BoundField HeaderText="First" DataField="FirstName" SortExpression="FirstName"></asp:BoundField> <asp:BoundField HeaderText="Hire Date" DataField="HireDate" SortExpression="HireDate" DataFormatString="{0:d}"></asp:BoundField> <asp:TemplateField HeaderText="Seniority"> <ItemTemplate> <%# ComputeSeniorityLevel(DateTime.Now – (DateTime)Eval("HireDate")) %> </ItemTemplate> </asp:TemplateField> </Columns> <SelectedRowStyle ForeColor="White" Font-Bold="True" BackColor="#CE5D5A"></SelectedRowStyle> <RowStyle BackColor="#F7F7DE"></RowStyle> </asp:GridView>
メモ ここに示す宣言型構文は、Visual Basic ASP.NET ページ用です。 C# を使用している場合は、TemplateField のメソッド呼び出しを宣言構文の前に示されている C# 構文に置き換えます。
残っているのは、 ComputeSeniorityLevel() メソッドを記述することです。 このメソッドは、整数の入力 (従業員が採用された日数) を受け入れ、年長のタイトルである文字列を返す必要があります。 図 27 は、ブラウザーを使用して表示した場合の ASP.NET ページの出力を示しています。
ComputeSeniorityLevel() メソッド (Visual Basic)
Function ComputeSeniorityLevel(ByVal ts As TimeSpan) As String Dim numberOfDaysOnTheJob As Integer = ts.Days If numberOfDaysOnTheJob >= 0 AndAlso numberOfDaysOnTheJob <= 1000 Then Return "Newbie" ElseIf numberOfDaysOnTheJob > 1000 _ AndAlso numberOfDaysOnTheJob <= 4000 Then Return "Associate" ElseIf numberOfDaysOnTheJob >= 4000 _ AndAlso numberOfDaysOnTheJob <= 8000 Then Return "One of the Regulars" Else Return "An Ol' Fogey" End If End Function ComputeSeniorityLevel() Method (C#) string ComputeSeniorityLevel(TimeSpan ts) { int numberOfDaysOnTheJob = ts.Days; if (numberOfDaysOnTheJob >= 0 && numberOfDaysOnTheJob <= 1000) return "Newbie"; else if (numberOfDaysOnTheJob > 1000 && numberOfDaysOnTheJob <= 4000) return "Associate"; else if (numberOfDaysOnTheJob >= 4000 && numberOfDaysOnTheJob <= 8000) return "One of the Regulars"; else return "An Ol' Fogey"; }
図 27
GridView 列内の Web コントロールの埋め込み
GridView 列内に 1 つ以上の Web コントロールを埋め込む場合は、多くの場合があります。 たとえば、1 対多リレーションシップの "1" として参加する GridView 内のデータベースのエンティティを表示する場合は、各行に関連する "多" レコードも表示する必要があります。 これを実現する方法の 1 つは、 BulletedList コントロールが埋め込まれた TemplateField を使用することです。 GridView を使用してこれを正確に実現する方法を見てみましょう。
Northwind データベースの Employees テーブルは、Terroritories テーブルとの一対多リレーションシップに参加します。各従業員には任意の数の地域が割り当てられます。 GridView に TemplateField を追加し、TemplateField に BulletedList を追加することで、従業員の関連する領域を BulletedList に表示できます。 DataGrid の結果の宣言構文は次のようになります。
<asp:GridView ID="employeesGridView" Runat="server" DataSourceID="employeesDataSource" AutoGenerateColumns="False" BorderWidth="1px" BackColor="White" GridLines="Horizontal" CellPadding="3" BorderStyle="None" BorderColor="#E7E7FF" OnRowDataBound="employeesGridView_RowDataBound"> <FooterStyle ForeColor="#4A3C8C" BackColor="#B5C7DE"></FooterStyle> <PagerStyle ForeColor="#4A3C8C" HorizontalAlign="Right" BackColor="#E7E7FF"></PagerStyle> <HeaderStyle ForeColor="#F7F7F7" Font-Bold="True" BackColor="#4A3C8C"></HeaderStyle> <AlternatingRowStyle BackColor="#F7F7F7"></AlternatingRowStyle> <Columns> <asp:BoundField HeaderText="LastName" DataField="LastName" SortExpression="LastName"></asp:BoundField> <asp:BoundField HeaderText="FirstName" DataField="FirstName" SortExpression="FirstName"></asp:BoundField> <asp:TemplateField HeaderText="Territories"><ItemTemplate> <asp:BulletedList ID="bltTerritories" Runat="server" DataTextField="TerritoryDescription" DataValueField="TerritoryDescription"> </asp:BulletedList> </ItemTemplate> </asp:TemplateField> </Columns> <SelectedRowStyle ForeColor="#F7F7F7" Font-Bold="True" BackColor="#738A9C"></SelectedRowStyle> <RowStyle ForeColor="#4A3C8C" BackColor="#E7E7FF"></RowStyle> </asp:GridView>
BulletedList の DataTextField プロパティが TerritoryDescription に設定されていることに注意してください。これは、担当地域の説明を提供する Northwind の Territoryes テーブルのフィールド名です。 最後の手順では、 BulletedList の DataSource を指定します。 これを実現するには、いくつかの方法があります。
- DataSource を宣言的に設定します。これは、前に調べた ImageField の例で行ったのと同じです。
- GridView の RowDataBound イベントのイベント ハンドラーを作成します。これは、各行に対してデータバインドとして 1 回発生します。 このイベント ハンドラーでは、 プログラムで BulletedList を参照し、その DataSource を割り当てて、 DataBind() メソッドを呼び出します。
この記事のダウンロードに含まれる例では、2 番目の方法を使用します。 具体的には、すべての領域を Page_Load イベント ハンドラーの DataView に読み込みます。RowDataBound イベント ハンドラーでは、現在のレコードの EmployeeID が読み取られ、DataView がこの値でフィルター処理されます。 このフィルター処理された DataView は、 BulletedList にバインドされます。
RowDataBound イベント ハンドラーと Page_Load イベント ハンドラー (Visual Basic)
Sub employeesGridView_RowDataBound(ByVal sender As Object, _ ByVal e As GridViewRowEventArgs) ' For each DataRow in the GridView, ' programmatically access the BulletedList, filter ' the DataView based on the GridView row's ' EmployeeID value and bind the filtered DataView ' to the BulletedList If e.Row.RowType = DataControlRowType.DataRow Then Dim bl As BulletedList = _ CType(e.Row.FindControl("bltTerritories"), BulletedList) territoryData.RowFilter = "EmployeeID = " & _ CType(e.Row.DataItem, DataRowView)("EmployeeID").ToString() bl.DataSource = territoryData bl.DataBind() End If End Sub Dim territoryData As DataView ' this DataView will hold all of the Territories, loaded at Page_Load Sub Page_Load(ByVal sender As Object, ByVal e As EventArgs) ' Load all of the territories into a DataView from the SqlDataSource territoryData = _ CType(territoriesDataSource.Select(DataSourceSelectArguments.Empty), DataView) End Sub
RowDataBound イベント ハンドラーと Page_Load イベント ハンドラー (C#)
void employeesGridView_RowDataBound(object sender, GridViewRowEventArgs e) { // For each DataRow in the GridView, // programmatically access the BulletedList, filter // the DataView based on the GridView row's // EmployeeID value and bind the filtered DataView // to the BulletedList if (e.Row.RowType == DataControlRowType.DataRow) { BulletedList bl = (BulletedList)e.Row.FindControl("bltTerritories"); territoryData.RowFilter = "EmployeeID = " + ((DataRowView) e.Row.DataItem)["EmployeeID"].ToString(); bl.DataSource = territoryData; bl.DataBind(); } } DataView territoryData; // this DataView will hold all of the Territories, loaded at Page_Load void Page_Load(object sender, EventArgs e) { // Load all of the territories into a DataView from the SqlDataSource territoryData = (DataView)territoriesDataSource.Select(DataSourceSelectArguments.Empty); }
データは、territoriesDataSource SqlDataSource の Select() メソッドを呼び出すことによって、Page_Load イベント ハンドラーに読み込まれます。 これにより、SqlDataSource コントロールによってカプセル化されたデータを含む DataView が返されます。 (次の ASP.NET ページの宣言構文を参照して 、territoriesDataSourceSqlDataSource の詳細を確認してください)。 RowDataBound イベント ハンドラーは、ヘッダーやフッターなど、DataRow以外を含む各行に対して発生します。 DataRowの処理にのみ関心があるため、If ステートメントを使用して、DataRow を確実に処理します。 その場合、 BulletedList はプログラムによって参照され、その DataSource プロパティはフィルター処理された territoryDataDataView に設定されます。
図 28 には、ブラウザーで表示したときの出力のスクリーンショットが含まれています。
図 28
<html xmlns="http://www.w3.org/1999/xhtml" > <head runat="server"> <title>Untitled Page</title> </head> <body> <form id="form1" runat="server"> <div> <asp:SqlDataSource ID="employeesDataSource" Runat="server" SelectCommand= "SELECT [EmployeeID], [LastName], [FirstName] FROM [Employees] ORDER BY [LastName], [FirstName]" ConnectionString="<%$ ConnectionStrings:NWConnectionString %>"> </asp:SqlDataSource> <asp:SqlDataSource ID="territoriesDataSource" Runat="server" SelectCommand="SELECT dbo.EmployeeTerritories.EmployeeID, dbo.Territories.TerritoryDescription FROM dbo.Territories INNER JOIN dbo.EmployeeTerritories ON dbo.Territories.TerritoryID = dbo.EmployeeTerritories.TerritoryID" ConnectionString="<%$ ConnectionStrings:NWConnectionString %>"> </asp:SqlDataSource> <asp:GridView ID="employeesGridView" Runat="server" DataSourceID="employeesDataSource" AutoGenerateColumns="False" BorderWidth="1px" BackColor="White" GridLines="Horizontal" CellPadding="3" BorderStyle="None" BorderColor="#E7E7FF" OnRowDataBound="employeesGridView_RowDataBound"> <FooterStyle ForeColor="#4A3C8C" BackColor="#B5C7DE"></FooterStyle> <PagerStyle ForeColor="#4A3C8C" HorizontalAlign="Right" BackColor="#E7E7FF"></PagerStyle> <HeaderStyle ForeColor="#F7F7F7" Font-Bold="True" BackColor="#4A3C8C"></HeaderStyle> <AlternatingRowStyle BackColor="#F7F7F7"></AlternatingRowStyle> <Columns> <asp:BoundField HeaderText="LastName" DataField="LastName" SortExpression="LastName"></asp:BoundField> <asp:BoundField HeaderText="FirstName" DataField="FirstName" SortExpression="FirstName"></asp:BoundField> <asp:TemplateField HeaderText="Territories"><ItemTemplate> <asp:BulletedList ID="bltTerritories" Runat="server" DataTextField="TerritoryDescription" DataValueField="TerritoryDescription"> </asp:BulletedList> </ItemTemplate> </asp:TemplateField> </Columns> <SelectedRowStyle ForeColor="#F7F7F7" Font-Bold="True" BackColor="#738A9C"></SelectedRowStyle> <RowStyle ForeColor="#4A3C8C" BackColor="#E7E7FF"></RowStyle> </asp:GridView> </div> </form> </body> </html>