ASP.NET 2.0のGridView

ASP.NET 2.0で追加されたGridViewだが、気に入らない点が二つあった。

  • 編集と削除は出来るが新しいデータの挿入は出来ない。
  • DataSourceが0件(Empty)のとき、コントロール自体が表示されない。

これに対して、以下の機能を追加した。

  • Footerを使って新しいデータを挿入できるようにした。
  • EmptyTemplateを使って、データ0件の時は新規データの挿入だけ出来るようにした。

実装のポイント

  • FooterTemplateを使ってGridViewの下部にInsert用入力欄を追加した。
  • FooterTemplateを使うことでデフォルトのasp:BoundFieldが使えなくなった。
  • 表示用にItemTemplateを使った。DataSourceを結びつけるのにEvalを使った。
  • 編集用にEditItemTemplateを使った。DataSourceと結びつけるのにBindを使った。また、BindするためにはIDを付けないといけなかった。
  • FooterTemplateを使った影響で、編集、削除、更新、キャンセルのボタンも自動で追加できなくなった。asp:ButtonのCommandNameにそれぞれEdit, Delete, Update, Cancelを指定してボタンを作成した。
  • DataSourceのデータが0件(Empty)の時のために、EmptyDataTemplateを使ってデータ入力領域を作成した。
  • Insert処理はGridViewと同じDataSourceのInsert機能を使った。

Default.aspx

<%@ Page Language="C#" AutoEventWireup="true"  CodeFile="Default.aspx.cs" Inherits="_Default" Trace="false"%>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">

<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:GridView ID="GridView1" runat="server" AllowPaging="True"
            AutoGenerateColumns="False" CellPadding="4" DataKeyNames="column1" DataSourceID="SqlDataSource1"
            ForeColor="#333333" ShowFooter="True">
            <FooterStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <RowStyle BackColor="#EFF3FB" />
            <Columns>
                <%-- 1列目:ボタン用 --%>
                <asp:TemplateField HeaderText="">
                    <ItemTemplate>
                        <%-- 編集/削除ボタン --%>                    
                        <asp:Button CommandName="Edit" Text="Edit" runat="server" />
                        <asp:Button CommandName="Delete" Text="Delete" runat="server" />
                    </ItemTemplate>
                    <EditItemTemplate>
                        <%-- 更新/キャンセルボタン --%>                    
                        <asp:Button CommandName="Update" Text="Update" runat="server" />
                        <asp:Button CommandName="Cancel" Text="Cancel" runat="server" />
                    </EditItemTemplate>
                    <FooterTemplate>
                        <asp:Button ID="FooterInsert" runat="server" OnClick="Insert_Click" Text="Insert" />
                    </FooterTemplate>
                </asp:TemplateField>
                <%-- 2列目:Column1用 --%>
                <asp:TemplateField HeaderText="Column1">
                    <ItemTemplate>
                        <asp:Label ID="column1" Text='<%# Eval("column1") %>' runat="server" />
                    </ItemTemplate>
                    <EditItemTemplate>
                        <%-- Column1はキーなのでEdit時もLabelのまま。Evalのままで良い。 --%>                    
                        <asp:Label ID="column1" Text='<%# Eval("column1") %>' runat="server" />
                    </EditItemTemplate>
                    <FooterTemplate>
                        <asp:TextBox ID="TextBox1a" runat="server"></asp:TextBox>
                    </FooterTemplate>
                </asp:TemplateField>
                <%-- 3列目:Column2用 --%>
                <asp:TemplateField HeaderText="Column2">
                    <ItemTemplate>
                        <%-- 表示時はEvalでDataSourceと結びつける --%>                    
                        <asp:Label Text='<%#Eval("column2") %>' runat="server" />
                    </ItemTemplate>
                    <EditItemTemplate>
                        <%-- 更新時はBindでDataSourceと結びつける。IDも必要。 --%>                    
                        <asp:TextBox ID="column2" Text='<%# Bind("column2") %>' runat="server" />
                    </EditItemTemplate>
                    <FooterTemplate>
                        <asp:TextBox ID="TextBox2a" runat="server"></asp:TextBox>
                    </FooterTemplate>
                </asp:TemplateField>
                <%-- 4列目:Column3用 --%>
                <asp:TemplateField HeaderText="Collumn3">
                    <ItemTemplate>
                        <asp:Label Text='<%#Eval("column3") %>' runat="server" />
                    </ItemTemplate>
                    <EditItemTemplate>
                        <asp:TextBox ID="column3" Text='<%# Bind("column3") %>' runat="server" />
                    </EditItemTemplate>
                    <FooterTemplate>
                        <asp:TextBox ID="TextBox3a" runat="server"></asp:TextBox>
                    </FooterTemplate>
                </asp:TemplateField>
            </Columns>
            <PagerStyle BackColor="#2461BF" ForeColor="White" HorizontalAlign="Center" />
            <%-- データ0件の時 --%>
            <EmptyDataTemplate>
                <table cellspacing="0" cellpadding="4" rules="all" border="1" style="color:#333333;border-collapse:collapse;">
                <tr style="color:White;background-color:#507CD1;font-weight:bold;">
                <th></th>
                <th>Column1</th>
                <th>Column2</th>
                <th>Column3</th>
                </tr>
                <tr style="background-color:#EFF3FB;">
                <td><asp:Button ID="EmptyInsert" runat="server" OnClick="Insert_Click" Text="Insert" /></td>
                <td><asp:TextBox ID="TextBox1" runat="server"></asp:TextBox></td>
                <td><asp:TextBox ID="TextBox2" runat="server"></asp:TextBox></td>
                <td><asp:TextBox ID="TextBox3" runat="server"></asp:TextBox></td>
                </tr>
                </table>
            </EmptyDataTemplate>
            <SelectedRowStyle BackColor="#D1DDF1" Font-Bold="True" ForeColor="#333333" />
            <HeaderStyle BackColor="#507CD1" Font-Bold="True" ForeColor="White" />
            <EditRowStyle BackColor="#D1DDF1" />
            <AlternatingRowStyle BackColor="White" />
        </asp:GridView>
        <%-- エラーメッセージ表示用 --%>
        <asp:Label ID="MsgBox1" runat="server" Text="Label"></asp:Label>
        <%-- データソース --%>        
        <asp:SqlDataSource ID="SqlDataSource1" runat="server" ConflictDetection="OverwriteChanges"
            ConnectionString="<%$ ConnectionStrings:mydbConnectionString %>" 
            DeleteCommand="DELETE [Table1] WHERE [column1] = @original_column1"
            InsertCommand="INSERT INTO [Table1] ([column1], [column2], [column3]) VALUES (@column1, @column2, @column3)"
            SelectCommand="SELECT [column1], [column2], [column3] FROM [Table1]" 
            UpdateCommand="UPDATE [Table1] SET [column2] = @column2, [column3] = @column3 WHERE [column1] = @original_column1">
            <DeleteParameters>
                <%-- カラム名にoriginal_とPrefixが付くと更新前データを表すようだ。
                Deleteの時はoriginal_column1にしか値がないので、間違えてwhere句にcolumn1を指定していたらdeleteが空振りした。 --%>
                <asp:Parameter Name="original_column1" Type="String" />
            </DeleteParameters>
            <UpdateParameters>
                <asp:Parameter Name="original_column1" Type="String" />
                <asp:Parameter Name="column2" Type="String" />
                <asp:Parameter Name="column3" Type="String" />
            </UpdateParameters>
            <InsertParameters>
                <asp:Parameter Name="column1" Type="String" />
                <asp:Parameter Name="column2" Type="String" />
                <asp:Parameter Name="column3" Type="String" />
            </InsertParameters>
        </asp:SqlDataSource>
    
    </div>
    </form>
</body>
</html>

Default.aspx.cs

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;

public partial class _Default : System.Web.UI.Page
{
    protected void Page_Load(object sender, EventArgs e)
    {
        //エラーメッセージをクリア
        MsgBox1.Text = "";
    }
    protected void Insert_Click(object sender, EventArgs e)
    {
        Control cnt = ((Control)sender).Parent;
        string id = ((Control)sender).ID;
        string id1 = "TextBox1";
        string id2 = "TextBox2";
        string id3 = "TextBox3";
        //Footerから呼ばれたときとEmptyDataTemplateから呼ばれたときの振り分け
        if (id.Equals("FooterInsert"))
        {
            id1 += "a";
            id2 += "a";
            id3 += "a";
        }
        string key = ((TextBox)cnt.FindControl(id1)).Text.Trim();
        if (key.Length == 0)
        {
            MsgBox1.Text = "column1は入力必須です。";
            return;
        }
        SqlDataSource1.InsertParameters["Column1"].DefaultValue = key;
        SqlDataSource1.InsertParameters["Column2"].DefaultValue = ((TextBox)cnt.FindControl(id2)).Text;
        SqlDataSource1.InsertParameters["Column3"].DefaultValue = ((TextBox)cnt.FindControl(id3)).Text;
        try
        {
            SqlDataSource1.Insert();
        }
        catch (System.Data.SqlClient.SqlException ex)
        {
            if (ex.Class == 14 && ex.Number == 2627)
            {
                MsgBox1.Text = "column1が重複しています。";
            }
            else
            {
                throw;
            }
        }
    }
}