昔「DataGrid, GridView に動的に列を追加」という記事を書きましたが、その記事よりスマートにできる方法を見つけたので以下に書いておきます。
先の記事ではどのようにしたかと言うと、DataGrid, GridView を構成している TableCellCollection の適切な位置に TableCell を追加するというプリミティブなやり方です。なので、列を追加するだけでもかなりコードを書かなければならないし、コントロールにデーターバインドしようとするとさらに面倒なことになります。
ところが最近になって Microsoft の Visual Studio 2008 用の MSDN ライブラリに「方法 : DataList Web サーバー コントロールのテンプレートを動的に作成する 」という記事があるのを見つけ、その方法が DataGrid, GridView にも使えることを知りました。
その MSDN ライブラリはもうネットには見つかりませんので、スクリーンショットを撮ってこの記事の下の方に貼っておきます。興味がありましたら見てください。
先の記事に書いたような TableCell を追加してなんちゃらという面倒なことをする必要はなく、TemplateColumn (DataGrid の場合) または TemplateField (GridView の場合) を生成し、それを DataGrid.Columns.Add メソッドまたは GridView.Columns.Add で追加するということで列の追加が可能です。
TemplateColumn, TemplateField の中身はユーザーコントロール (.ascx) から作成します。作成したユーザーコントロールから TemplateControl.LoadTemplate メソッドで ITemplate インターフェイスのインスタンスを生成し、当該テンプレート (ItemTemplate, AlternatingItemTemplate 等) に代入してやります。
ユーザーコントロール内に配置したコントロールには <%# Eval("Name") %> というようなデータバインド式を含めることができます。そうしておけば、静的にデータバインド式を使った場合と同様に、自動的にデータソースからデータを取得して表示されます。
具体例は以下の通りです。上の画像を表示したコードで、データソースに SQL Server のサンプルデータベース Northwind の Products テーブルを使って、その PtoductName 列と Discontinued 列を動的に追加した TemplateColumn, TemplateField に表示しています。
(1) ユーザーコントロールの作成
テンプレートの中身のコントロールを配置したユーザーコントロール (.ascx) を作成します。以下の例では CheckBox と Label をテンプレートの中身として配置しています。データバインド式を含めているところにも注目してください。
<%@ Control Language="C#" AutoEventWireup="true"
CodeBehind="NewTemplate.ascx.cs"
Inherits="WebApplication2.NewTemplate" %>
製造中止:
<asp:CheckBox ID="CheckBox1" runat="server"
Checked='<%# Eval("Discontinued") %>'
Enabled="false" />
/
製品名:
<asp:Label ID="Label1" runat="server"
Text='<%# Eval("ProductName") %>'>
</asp:Label>
ユーザーコントロールの名前は、ここでは NewTemplate.ascx としました。名前は任意に設定して構いませんが .aspx.cs の LoadTemplate メソッドの引数にその名前を使いますので注意してください。
(2) TemplateColumn, TemplateField の追加
.aspx.cs
DataGrid は TemplateColumn を、GridView は TemplateField を使うという違いがあり、それによる若干の違いがありますので注意してください。
using System;
using System.Web.UI;
using System.Web.UI.WebControls;
namespace WebApplication2
{
public partial class LoadTemplate : System.Web.UI.Page
{
protected void Page_Init(object sender, EventArgs e)
{
// DataGrid に TemplateColumn を追加
var templateColumn = new TemplateColumn();
templateColumn.HeaderText = "動的に追加した TemplateColumn";
templateColumn.ItemTemplate = LoadTemplate("NewTemplate.ascx");
DataGrid1.Columns.Add(templateColumn);
// GridView に TemplateField を追加
var templateField = new TemplateField();
templateField.HeaderText = "動的に追加した TemplateField";
templateField.ItemTemplate = LoadTemplate("NewTemplate.ascx");
GridView1.Columns.Add(templateField);
}
}
}
.aspx
マスターページを使っています。ほぼ 100% デザイナで自動生成したコードで、DB の ProductID のみを表示するように作成しました。ProductName と Discontinued は上の .aspx.cs で動的に追加した列に表示します。
<%@ Page Title="" Language="C#" MasterPageFile="~/Site.Master"
AutoEventWireup="true" CodeBehind="LoadTemplate.aspx.cs"
Inherits="WebApplication2.LoadTemplate" %>
<asp:Content ID="Content1" ContentPlaceHolderID="MainContent" runat="server">
<asp:SqlDataSource ID="SqlDataSource1"
runat="server"
ConnectionString="<%$ ConnectionStrings:NORTHWINDConnectionString %>"
SelectCommand="SELECT TOP 10 [ProductID], [ProductName], [Discontinued]
FROM [Products]">
</asp:SqlDataSource>
<h3>DataGrid</h3>
<asp:DataGrid ID="DataGrid1"
runat="server"
AutoGenerateColumns="False"
DataSourceID="SqlDataSource1">
<Columns>
<asp:BoundColumn DataField="ProductID"
HeaderText="ProductID" />
</Columns>
</asp:DataGrid>
<h3>GridView</h3>
<asp:GridView ID="GridView1"
runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID"
DataSourceID="SqlDataSource1">
<Columns>
<asp:BoundField DataField="ProductID"
HeaderText="ProductID"
InsertVisible="False" ReadOnly="True"
SortExpression="ProductID" />
</Columns>
</asp:GridView>
</asp:Content>
最後に、上にも書きましたが、参考にした Visual Stidio 2008 の MSDN ライブラリのスクリーンショットを下に貼っておきます。