ASP.NET 2.0 の GridView の例: GridView で基になるデータを編集する

 

ここをクリックして TOC に戻ります。

GridView の基になるデータを削除することに加えて、もう 1 つの一般的なニーズは、エンド ユーザーが GridView に表示されるデータを編集できるようにすることです。 ASP.NET 1.x の DataGrid コントロールでは、データの編集は確実に可能ですが、3 つのイベント ハンドラーを作成し、12 行ほどのコードを記述する必要があります。 GridView と ASP.NET 2.0 を使用すると、1 行のコードを記述せずに編集可能な GridView を作成できます。 必要なすべての機能は GridView 内にカプセル化されます。

GridView を使用すると、行ごとに編集できます。 編集可能な GridView には、各行に [編集] ボタンを含む追加の列が含まれています。 エンド ユーザーが [編集] ボタンをクリックすると、その行が編集可能になり、[編集] ボタンが [更新] ボタンと [キャンセル] ボタンに変わり、その他の列が [テキスト ボックス] になります。 その後、エンド ユーザーは 1 つ以上の列値を更新し、[更新] をクリックして変更を保存できます。

このセクションでは、4 つの例について説明します。 最初のデモでは、SqlDataSource からデータを取得する編集可能な GridView を作成する方法について説明します。 次に、ObjectDataSource から編集可能な GridView を作成する方法について説明します。 ご想像のとおり、ObjectDataSource から取得したデータを含む編集可能な GridView を作成する場合、基になるデータ アクセスレイヤー クラスは適切な Update メソッドを提供する必要があります。 Update メソッドに必要なシグネチャを確認し、このメソッドを使用するように ObjectDataSource を構成する方法を確認します。 最後の 2 つのデモでは、 GridView 列の編集インターフェイスをカスタマイズする方法について説明します。 既定では、TextBoxes には検証コントロールは関連付けされていませんが、ビジネス ルールでは特定の検証が必要な場合があります。 特定のフィールドが必要な場合や、特定の形式で入力する必要がある場合があります。 また、編集インターフェイスとしての標準の TextBox は受け入れられない場合があります。また、TextBox をデータバインド DropDownList に置き換える例も見ていきます。

SqlDataSource から取得した GridView データの編集

SqlDataSource からのデータを含む編集可能な GridView の作成は、驚くほど簡単です。 開始するには、 GridViewSqlDataSource に、適切なパラメーターを含む UpdateCommand が含まれている必要があります。 「GridView の基になるデータの削除」セクションで説明したように、このような SqlDataSource の作成は、図 35 に示すダイアログ ボックスの [挿入、更新、および削除ステートメントの生成] を確認するのと同じくらい簡単です。 (このダイアログ ボックスにアクセスするには、 SqlDataSource ウィザードの 2 番目の手順で [詳細設定] ボタンをクリックします)。

削除の例と同様に、Insert ステートメント、Update ステートメント、Delete ステートメントの生成をチェックすると、UPDATE ステートメントだけでなく、INSERT ステートメントと DELETE ステートメントも作成されます。 これらは、既存のデータの編集のみに限定された GridView を作成する場合は、安全に削除できます。 UPDATE ステートメントを使用して SqlDataSource を構成すると、編集可能な GridView を簡単に作成できます。 新しい GridView をページに追加し、スマート タグから [編集を有効にする] チェック ボックスをオンにします (図 39 を参照)。 これにより、[編集] ボタンを使用して GridView に CommandField が追加されます。

大きな画像については、ここをクリックしてください。

図 39 (画像をクリックすると大きな画像が表示されます)

これですべて完了です。 図 40 と図 41 は、編集可能な GridView の動作のスクリーンショットを示しています。 図 40 は、編集可能な状態の GridView を示しています。 図 41 は、[編集] ボタンがクリックされた後の画面を示しています。[編集] ボタンをクリックすると、[更新] ボタンと [キャンセル] ボタンが表示され、編集可能な行の列はテキスト ボックスとしてレンダリングされることに注意してください。

ms972948.gridview_fg40(en-us,MSDN.10).gifms972948.gridview_fg40

図 40

ms972948.gridview_fg41(en-us,MSDN.10).gifms972948.gridview_fg41

図 41

図 41 では、ProductID 列が編集できないことがわかります。 次の ASP.NET ページの宣言構文に示すように、 GridView 列を編集不可としてマークするには、その ReadOnly プロパティを True に設定します。 以下のマークアップを突き抜ける場合は、次の点に注意してください。

  • SqlDataSource には、UpdateCommand プロパティと <UpdateParameters> セクションが含まれています。このセクションには、UPDATE ステートメントで必要なパラメーターが記述されています。 この UpdateCommandSqlDataSource に追加し忘れた場合、編集可能な GridView を作成することはできません。
  • UpdateParameters> セクションの<asp:Parameter> タグは<、既定では、GridView に入力された空白の文字列を NULL に変換します。 この動作をオーバーライドするには、必要なパラメーターに 対して ConvertEmptyStringToNull プロパティを False に 設定します。
  • 関連付けられた BoundField の ReadOnly="True" 設定により、ProductID 列は編集できません。
  • この例では、 GridView の既定の編集インターフェイスを示します。これにより、編集可能なすべての列が TextBoxes としてレンダリングされます。
<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
</script>
<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="productDataSource" Runat="server"
            SelectCommand="SELECT [ProductName], [ProductID], 
            [UnitPrice], [UnitsInStock] FROM [Products]"
            UpdateCommand="UPDATE [Products] SET [ProductName] = 
              @ProductName, [UnitPrice] = @UnitPrice, [UnitsInStock] = 
              @UnitsInStock WHERE [ProductID] = @original_ProductID"
            ConnectionString="<%$ ConnectionStrings:NWConnectionString %>">
            <UpdateParameters>
                <asp:Parameter Type="String" 
                  Name="ProductName"></asp:Parameter>
                <asp:Parameter Type="Decimal" 
                  Name="UnitPrice"></asp:Parameter>
                <asp:Parameter Type="Int16" 
                  Name="UnitsInStock"></asp:Parameter>
                <asp:Parameter Type="Int32" Name="ProductID"></asp:Parameter>
            </UpdateParameters>
        </asp:SqlDataSource>
        <asp:GridView ID="GridView1" Runat="server" 
            DataSourceID="productDataSource" DataKeyNames="ProductID"
            AutoGenerateColumns="False" AllowPaging="True" 
            BorderWidth="1px" BackColor="White"
            CellPadding="4" BorderStyle="None" BorderColor="#3366CC">
            <FooterStyle ForeColor="#003399" 
               BackColor="#99CCCC"></FooterStyle>
            <PagerStyle ForeColor="#003399" HorizontalAlign="Left" 
               BackColor="#99CCCC"></PagerStyle>
            <HeaderStyle ForeColor="#CCCCFF" Font-Bold="True" 
               BackColor="#003399"></HeaderStyle>
            <Columns>
                <asp:CommandField ShowEditButton="True"></asp:CommandField>
                <asp:BoundField ReadOnly="True" HeaderText="ProductID" 
                    InsertVisible="False" DataField="ProductID"
                    SortExpression="ProductID"></asp:BoundField>
                <asp:BoundField HeaderText="Product" 
                    DataField="ProductName" 
                    SortExpression="ProductName"></asp:BoundField>
                <asp:BoundField HeaderText="Unit Price" 
                    DataField="UnitPrice" SortExpression="UnitPrice">
                    <ItemStyle HorizontalAlign="Right"></ItemStyle>
                </asp:BoundField>
                <asp:BoundField HeaderText="Units In Stock" 
                   DataField="UnitsInStock" SortExpression="UnitsInStock">
                    <ItemStyle HorizontalAlign="Right"></ItemStyle>
                </asp:BoundField>
            </Columns>
            <SelectedRowStyle ForeColor="#CCFF99" Font-Bold="True" 
                BackColor="#009999"></SelectedRowStyle>
            <RowStyle ForeColor="#003399" BackColor="White"></RowStyle>
        </asp:GridView>
    
    </div>
    </form>
</body>
</html>

上記の例は、[オプティミスティック コンカレンシーを使用する] チェック ボックスをオン にせずに 作成されました。 [挿入、更新、および削除ステートメントの生成] チェックボックスと共にオンにした場合、SqlDataSourceUpdateCommand には、より徹底的な WHERE 句が含まれています。 WHERE [ProductID] = @original\_ProductIDを使用する代わりに、オプティミスティック コンカレンシーを使用すると、WHERE 句は次のように読み取られます。

WHERE [ProductID] = @original_ProductID AND [ProductName] = 
  @original_ProductName AND [UnitPrice] = @original_UnitPrice AND 
  [UnitsInStock] = @original_UnitsInStock

これにより、ユーザーが GridView 行の [編集] ボタンをクリックしてから [更新] ボタンをクリックしてから、別のユーザーがその特定の行を変更した場合、UPDATE が発生するのを防ぐことができます。

ObjectDataSource から取得した GridView データの編集

ObjectDataSource にバインドされた GridView からデータを削除する場合と同様に、ObjectDataSource にバインドされた編集可能な GridView を作成する場合、ASP.NET ページの作成に必要な変更はほとんどありません。 ほとんどの作業は、更新を処理するためにデータ アクセス層クラスにメソッドを追加する際に必要です。

Delete の例と同様に、 Update メソッドのシグネチャは ObjectDataSourceConflictDetection プロパティによって異なります。 既定の動作 (OverwriteChanges) を使用している場合、 Update メソッドは、元の主キー フィールドと、主キー以外の更新された値のパラメーターを受け入れる必要があります。 一方、 CompareAllValues を使用する場合、 Update メソッドは、更新されたキーフィールドと元の主キー以外のフィールド値の両方を、元の主キー フィールドと共に受け入れる必要があります。

混乱を明確にするために、具体的な例を見てみましょう。 前のデモと同様に、Northwind Products テーブルのフィールドを表示する GridView を作成しましょう。 ただし、このデモでは、 Update メソッドを ProductDAL クラスに追加する必要があります。 (ObjectDataSource を調べるときに、DataSource コントロールを使用したデータへのアクセス セクションに ProductDAL クラスを作成したことを思い出してください)。OverwriteChanges 動作を使用していると仮定すると、Update メソッドは次のようになります。

The UpdateProduct Method (Visual Basic)
Public Class ProductDAL
    ...
    Public Shared Sub UpdateProduct(ByVal original_ProductID As Integer, _
      ByVal productName As String, ByVal unitPrice As Decimal, _
      ByVal unitsInStock As Integer)
        'Updates the Products table
        Dim sql As String = "UPDATE Products SET ProductName = " & _
          " @ProductName, UnitPrice = @UnitPrice, UnitsInStock = " & _
          "@UnitsInStock WHERE ProductID = @ProductID"
        Using myConnection As _
          New SqlConnection( _
ConfigurationManager.ConnectionStrings("NWConnectionString").ConnectionString)
            Dim myCommand As New SqlCommand(sql, myConnection)
            myCommand.Parameters.Add( _
             New SqlParameter("@ProductName", productName))
            myCommand.Parameters.Add(New SqlParameter("@UnitPrice", _
             unitPrice))
            myCommand.Parameters.Add(New SqlParameter("@UnitsInStock", _
              unitsInStock))
            myCommand.Parameters.Add(New SqlParameter("@ProductID", _
              original_ProductID))
            myConnection.Open()
            myCommand.ExecuteNonQuery()
            myConnection.Close()
        End Using
    End Sub
End Class
The UpdateProduct Method (C#)
public class ProductDAL
{
    ...
    
    public static void UpdateProduct(int original_ProductID, 
      string productName, decimal unitPrice, int unitsInStock)
    {
        // Updates the Products table
        string sql = "UPDATE Products SET ProductName = " +
           "@ProductName, UnitPrice = @UnitPrice, UnitsInStock = " + 
           "@UnitsInStock WHERE ProductID = @ProductID";
        using (SqlConnection myConnection = 
            new 
SqlConnection(ConfigurationManager.ConnectionStrings["NWConnectionString"].ConnectionString))
        {
            SqlCommand myCommand = new SqlCommand(sql, myConnection);
            myCommand.Parameters.Add(new SqlParameter("@ProductName", 
              productName));
            myCommand.Parameters.Add(new SqlParameter("@UnitPrice", 
              unitPrice));
            myCommand.Parameters.Add(new SqlParameter("@UnitsInStock", 
               unitsInStock));
            myCommand.Parameters.Add(new SqlParameter("@ProductID", 
               original_ProductID));
            myConnection.Open();
            myCommand.ExecuteNonQuery();
            myConnection.Close();
        }
    }
}

ご覧のように、Update メソッド UpdateProducts()は、gridView の編集可能な各列 (productNameunitPriceunitsInStock) と共にoriginal_ProductIDを受け取ります。 ObjectDataSourceCompareAllValues に構成した場合は、次のようなシグネチャを持つ Update メソッドが必要です。

' Visual Basic .NET
Public Shared Sub UpdateProduct(ByVal original_ProductID as Integer, _
  ByVal original_productName as String, _
  ByVal decimal original_unitPrice as Decimal, _
  ByVal original_unitsInStock as Integer, _
  ByVal productName as String, ByVal unitPrice as Decimal, _
  ByVal unitsInStock as Integer)
   ...
End Sub
// C#
public static void UpdateProduct(int original_ProductID, 
  string original_productName, decimal original_unitPrice, 
  int original_unitsInStock, string productName, decimal unitPrice, 
  int unitsInStock)
{
   ...
}

CompareAllValues アプローチを使用する場合は、DAL 開発者は、基になるデータがユーザーの編集中に行われたかどうかを判断し、その場合は問題を解決する方法を決定するために必要な手順を実行する必要があります。

DAL クラスに適切な Update メソッドが与えられたら、最後の手順は、この Update メソッドを利用するように ObjectDataSource を構成することです。 これを行うには、 ObjectDataSource のウィザードから [UPDATE] タブに移動し、適切な方法を選択します (図 42 を参照)。

ms972948.gridview_fg42(en-us,MSDN.10).gifms972948.gridview_fg42

図 42

これですべて完了です。 エンド ユーザーの観点からは、SqlDataSource にバインドされている GridView を更新することは、ObjectDataSource にバインドされている GridView を更新するのと変わりはありません。 図 40 と 41 を参照して、編集可能な GridView の動作を確認できます。 ASP.NET ページの宣言構文を次に示します。 SqlDataSource の例と同様に、ASP.NET ページにはコードは必要ありません。

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
</script>
<html xmlns="http://www.w3.org/1999/xhtml" >
<head runat="server">
    <title>Untitled Page</title>
</head>
<body>
    <form id="form1" runat="server">
    <div>
        <asp:ObjectDataSource ID="productDataSource" 
            Runat="server" TypeName="ProductDAL"
            SelectMethod="GetProducts" EnablePaging="True" 
            SelectCountMethod="TotalNumberOfProducts"
            UpdateMethod="UpdateProduct">
            <UpdateParameters>
                <asp:Parameter Type="Int32" Name="ProductID"></asp:Parameter>
                <asp:Parameter Type="String" 
                  Name="productName"></asp:Parameter>
                <asp:Parameter Type="Decimal" 
                  Name="unitPrice"></asp:Parameter>
                <asp:Parameter Type="Int32" 
                  Name="unitsInStock"></asp:Parameter>
            </UpdateParameters>
        </asp:ObjectDataSource>
    <asp:GridView ID="GridView1" Runat="server" 
             DataSourceID="productDataSource" 
             DataKeyNames="ProductID"
            AutoGenerateColumns="False" AllowPaging="True" 
BorderWidth="1px" BackColor="White"
            CellPadding="4" BorderStyle="None" BorderColor="#3366CC">
            <FooterStyle ForeColor="#003399" 
               BackColor="#99CCCC"></FooterStyle>
            <PagerStyle ForeColor="#003399" HorizontalAlign="Left" 
               BackColor="#99CCCC"></PagerStyle>
            <HeaderStyle ForeColor="#CCCCFF" Font-Bold="True" 
               BackColor="#003399"></HeaderStyle>
            <Columns>
                <asp:CommandField ShowEditButton="True"></asp:CommandField>
                <asp:BoundField ReadOnly="True" 
                   HeaderText="ProductID" InsertVisible="False" 
                   DataField="ProductID"
                    SortExpression="ProductID"></asp:BoundField>
                <asp:BoundField HeaderText="Product" 
DataField="ProductName" SortExpression="ProductName"></asp:BoundField>
                <asp:BoundField HeaderText="Unit Price" 
                   DataField="UnitPrice" SortExpression="UnitPrice">
                    <ItemStyle HorizontalAlign="Right"></ItemStyle>
                </asp:BoundField>
                <asp:BoundField HeaderText="Units In Stock" 
                    DataField="UnitsInStock" 
                    SortExpression="UnitsInStock">
                    <ItemStyle HorizontalAlign="Right"></ItemStyle>
                </asp:BoundField>
            </Columns>
            <SelectedRowStyle ForeColor="#CCFF99" Font-Bold="True" 
               BackColor="#009999"></SelectedRowStyle>
            <RowStyle ForeColor="#003399" BackColor="White"></RowStyle>
        </asp:GridView>
    </div>
    </form>
</body>
</html>

編集インターフェイスのカスタマイズ

過去 2 つの例は、編集可能な GridView を簡単に作成する方法を示しています。 ただし、 GridView の既定の編集機能の欠点の 1 つは、編集インターフェイスが最適ではない可能性があることです。 既定では、編集可能な GridView 行のすべての編集可能な列は TextBox としてレンダリングされ、どの検証ロジックも関連付けされていません。 ただし、実際の状況では、多くの場合、編集可能な入力に検証ロジックを追加したり、TextBox 以外の編集コントロールを使用したりする必要があります。

GridView の編集インターフェイスを変更する方法に関係なく、これを実現する方法は、BoundFields ではなく TemplateFields を使用することです。 BoundField は、常に編集モードで TextBox を表示します。 ただし、TemplateField を使用すると、編集インターフェイスの機能を正確に指定できます。

このセクションでは、 GridView の編集インターフェイスをカスタマイズする 2 つの例について説明します。 最初に、検証コントロールを追加する方法について説明します。2 つ目では、代わりに標準の TextBox を DropDownList に置き換える方法について説明します。

編集インターフェイスへの検証コントロールの追加

GridView の既定の編集インターフェイスには検証ロジックがないため、エンド ユーザーは編集可能な行の TextBox に任意の種類のデータを入力できます。 最後の 2 つの編集可能な GridView の例を振り返って、ユーザーが製品の単価に Sam という値を入力した場合はどうなるかを考えてみましょう。 データベースで 10 進フィールドを文字列値に設定できないため、このようなアクションでは例外が発生します。 同様に、単価が 0 より大きい、製品名が必須フィールドなど、特定のビジネス ルールを適用する場合があります。

GridView の編集インターフェイスは、列単位のレベルで操作できます。 これを行うには、BoundFields の代わりに TemplateFields を使用し、使用する編集可能なインターフェイスを指定します。 以前の編集可能な GridViewSqlDataSource の例にバインドして、Product、Unit Price、Units In Stock 列の検証コントロールを利用することで、これがどのように行われるかを調べてみましょう。

最初の手順では、これら 3 つの列を TemplateFields に変換します。 これを行う最も簡単な方法は、デザイン ビューに移動し、 GridView のスマート タグの [列の編集] リンクをクリックすることです。 左下隅の列リストから BoundField を選択すると、[このフィールドを TemplateField に変換する] リンクが表示されます (図 43 を参照)。 先に進み、[製品]、[単価]、[在庫単位] 列を TemplateFields に変換します。

ms972948.gridview_fg43(en-us,MSDN.10).gifms972948.gridview_fg43

図 43

前に説明したように、 GridView 行を編集可能にすると、BoundFields は TextBoxes になります。 一方、TemplateFields は、TemplateField の EditItemTemplate で指定した HTML マークアップと Web コントロール構文をレンダリングします。 TemplateField の EditItemTemplate を編集するには、 GridView のスマート タグから [テンプレートの編集] リンクを選択します。 これにより、編集する列のテンプレートを選択できます。

メモ TemplateField に EditItemTemplate がない場合、GridView 列は編集できません。

デザイン ビューを使用して BoundFields を TemplateFields に変換すると、TemplateField には TextBox を含む EditItemTemplate が含まれていることに注意してください。 図 44 は、Product 列の EditItemTemplate の編集を示しています。 存在する TextBox は自分で追加されたのではなく、TemplateField に変換するときに自動的にそこに配置されました。

ms972948.gridview_fg44(en-us,MSDN.10).gifms972948.gridview_fg44

図 44

EditItemTemplate に検証コントロールを追加するには、ツールボックスから EditItemTemplate に適切な検証コントロールをドラッグ アンド ドロップするだけです。 Product EditItemTemplateRequiredFieldValidator を追加し、[単価] 列と [在庫単位] 列に CompareValidator を追加して、入力したデータが適切な型であることを確認します。 最後に、 ValidationSummary コントロールをページに追加して、無効なデータに関する情報をユーザーに表示します。

検証コントロールを追加すると、ASP.NET ページの宣言構文は次のようになります。

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
</script>
<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="productDataSource" 
              Runat="server" 
 ConnectionString="<%$ ConnectionStrings:NWConnectionString %>"
                UpdateCommand="UPDATE [Products] SET [ProductName] = 
@ProductName, [UnitPrice] = @UnitPrice, 
[UnitsInStock] = @UnitsInStock WHERE [ProductID] = @original_ProductID"
                SelectCommand="SELECT [ProductName], [ProductID], 
  [UnitPrice], [UnitsInStock] FROM [Products]">
                <UpdateParameters>
                    <asp:Parameter Type="String" 
                     Name="ProductName"></asp:Parameter>
                    <asp:Parameter Type="Decimal" 
                      Name="UnitPrice"></asp:Parameter>
                    <asp:Parameter Type="Int16" 
                      Name="UnitsInStock"></asp:Parameter>
                    <asp:Parameter Type="Int32" 
                      Name="ProductID"></asp:Parameter>
                </UpdateParameters>
            </asp:SqlDataSource>
            <asp:GridView ID="GridView1" Runat="server" 
                BorderColor="#3366CC" BorderStyle="None"
                CellPadding="4" BackColor="White" 
                 BorderWidth="1px" AllowPaging="True" 
                 AutoGenerateColumns="False"
                DataKeyNames="ProductID" DataSourceID="productDataSource">
                <FooterStyle ForeColor="#003399" 
                      BackColor="#99CCCC"></FooterStyle>
                <PagerStyle ForeColor="#003399" HorizontalAlign="Left" 
                       BackColor="#99CCCC"></PagerStyle>
                <HeaderStyle ForeColor="#CCCCFF" 
                  Font-Bold="True" BackColor="#003399"></HeaderStyle>
                <Columns>
                    <asp:CommandField 
                       ShowEditButton="True"></asp:CommandField>
                    <asp:BoundField ReadOnly="True" 
                       HeaderText="ProductID" InsertVisible="False" 
                       DataField="ProductID"
                        SortExpression="ProductID"></asp:BoundField>
                    <asp:TemplateField SortExpression="ProductName" 
                      HeaderText="Product"><EditItemTemplate>
                        <asp:TextBox ID="editProductName" 
                         Runat="server" 
                         Text='<%# Bind("ProductName") %>'></asp:TextBox>
                        <asp:RequiredFieldValidator 
                          ID="RequiredFieldValidator1" 
                          Runat="server" 
                       ErrorMessage="You must provide a Product Name."
                            ControlToValidate="editProductName">
                            *</asp:RequiredFieldValidator>
                    </EditItemTemplate>
                        <ItemTemplate>
                            <asp:Label Runat="server" 
                         Text='<%# Bind("ProductName") %>' 
                         ID="Label3"></asp:Label>
                        </ItemTemplate>
                    </asp:TemplateField>
                    <asp:TemplateField SortExpression="UnitPrice" 
                      HeaderText="Unit Price"><EditItemTemplate>
                        <asp:TextBox ID="editUnitPrice" Runat="server" 
                          Text='<%# Bind("UnitPrice", "{0:#,##0.00}") %>' 
                          Columns="6"></asp:TextBox>
                        <asp:CompareValidator ID="CompareValidator1" 
                          Runat="server" 
ErrorMessage="You must provide a valid currency value for the Unit Price."
                            ControlToValidate="editUnitPrice" 
                   Operator="DataTypeCheck" Type="Currency">
                            *</asp:CompareValidator>
                    </EditItemTemplate>
                        <ItemStyle HorizontalAlign="Right"></ItemStyle>
                        <ItemTemplate>
                            <asp:Label Runat="server" 
               Text='<%# Bind("UnitPrice", "{0:c}") %>' 
               ID="Label1"></asp:Label>
                        </ItemTemplate>
                    </asp:TemplateField>
                    <asp:TemplateField SortExpression="UnitsInStock" 
                     HeaderText="Units In Stock"><EditItemTemplate>
                        <asp:TextBox ID="editUnitsInStock" 
                 Runat="server" 
                 Text='<%# Bind("UnitsInStock") %>'
                            Columns="4"></asp:TextBox>
                        <asp:CompareValidator ID="CompareValidator2" 
                          Runat="server" 
ErrorMessage="You must provide a valid integer for Units In Stock."
                            ControlToValidate="editUnitsInStock" 
                            Operator="DataTypeCheck" Type="Integer">
                            *</asp:CompareValidator>
                    </EditItemTemplate>
                        <ItemStyle HorizontalAlign="Right"></ItemStyle>
                        <ItemTemplate>
                            <asp:Label Runat="server" 
              Text='<%# Bind("UnitsInStock") %>' 
              ID="Label2"></asp:Label>
                        </ItemTemplate>
                    </asp:TemplateField>
                </Columns>
                <SelectedRowStyle ForeColor="#CCFF99" 
                   Font-Bold="True" 
                   BackColor="#009999"></SelectedRowStyle>
                <RowStyle ForeColor="#003399" BackColor="White"></RowStyle>
            </asp:GridView>
        </div>
    <div>
        <asp:ValidationSummary ID="ValidationSummary1" Runat="server" />
    
    </div>
    </form>
</body>
</html>

GridView 行を編集するときに、編集可能な行の正しいフィールド値が TextBox にどのように設定されているか疑問に思うかもしれません。 TextBox Web コントロールの宣言構文でわかるように、マジックは Bind() メソッドにあります。 TextBox の Text プロパティを %# Bind(fieldName) %> に<設定すると、TextBox にフィールド fieldName の値が表示されます。 この同じ構文は、TemplateFields の ItemTemplates の Label Web コントロールでも使用されます。

図 45 は、強化された編集可能な GridView のスクリーンショットを示しています。 フィールドに無効な値が入力されている場合、基になるデータは更新されず、 GridView の下部にある検証の概要は、存在する問題を示します。

大きな画像については、ここをクリックしてください。

図 45 (画像をクリックすると大きな画像が表示されます)

編集インターフェイスに代替 Web コントロールを使用する

特定のシナリオでは、TextBox が理想的な編集インターフェイスではない可能性があります。 たとえば、日付フィールドを編集する場合、ユーザーは TextBox に日付を入力する必要なく、カレンダー Web コントロールを使用して日付を選択するときにエラーが発生しにくくなります。 同様に、ルックアップ データの場合、通常は別のデータベース テーブルで定義される一連の有効な値に制限されているデータは、一般的に DropDownList に最適な編集インターフェイスです。

Northwind データベースの Products テーブルには、製品を Categories テーブルのカテゴリに関連付ける CategoryID フィールドが含まれています。 これは、DropDownList が編集インターフェイスに適している主要なケースです。 DropDownList を提供するように編集インターフェイスを変更することは非常に簡単で、ソース コードはまったく必要ありません。

まず、製品のリストと製品に関連付けられているカテゴリを返すように構成された SqlDataSource を作成します。 これを実現するには、DataSource ウィザードでカスタム SQL SELECT ステートメント (結合を使用して製品の CategoryID の正しい CategoryName を取得するステートメント) を使用する必要があります。 SQL クエリは次のようになります。

SELECT dbo.Products.ProductID, dbo.Products.ProductName, 
       dbo.Products.CategoryID, dbo.Categories.CategoryName 
FROM dbo.Products 
   INNER JOIN dbo.Categories ON 
      dbo.Products.CategoryID = dbo.Categories.CategoryID

UpdateCommand を含めるために SqlDataSource を作成する際に注意してください。 UpdateCommand を指定し忘れた場合、GridView を編集可能にすることはできません。

次に、 GridView を追加し、 SqlDataSource にバインドして、編集可能にします。 [ProductName] フィールドと [CategoryName] フィールドだけを残したまま、 GridView から ProductID 列と CategoryID 列を自由に削除できます。

次のタスクは、CategoryName 列の編集インターフェイスをカスタマイズして、TextBox ではなくカテゴリの DropDownList を使用するようにすることです。 前のセクションで説明したように、カスタマイズされた編集インターフェイスを作成するには TemplateField が必要であるため、CategoryName 列を TemplateField に変換します。 次に、デザイン ビューから CategoryName 列の EditItemTemplate を編集します。

CategoryName EditItemTemplate には TextBox が含まれている必要があります。 先に進み、これを削除し、利用可能なカテゴリの DropDownList を持つ必要なコントロールを追加します。 SqlDataSource を、Categories テーブルから CategoryID フィールドと CategoryName フィールドを選択するように構成されたページにドラッグ アンド ドロップするだけです。 次に、 EditItemTemplate に DropDownList を追加し、この SqlDataSource にバインドします (図 46 を参照)。

ms972948.gridview_fg46(en-us,MSDN.10).gifms972948.gridview_fg46

図 46

この時点でブラウザーの ASP.NET ページにアクセスすると、 GridView の行を編集するときに、CategoryName 列にすべてのカテゴリの DropDownList が表示されますが、行のカテゴリに関係なく、DropDownList の最初のカテゴリが常に選択されていることがわかります。 行が編集可能になると、DropDownList の SelectedValue が行の CategoryID 値に設定されるように、ページを改善する必要があります。 これは、次の TemplateField のマークアップに示すように、前の例で見た Bind() メソッドを使用して実現できます。

<asp:TemplateField SortExpression="CategoryName" HeaderText="CategoryName">
   <EditItemTemplate>
        <asp:DropDownList ID="DropDownList1" Runat="server" 
          DataSourceID="categoryDataSource"
            DataTextField="CategoryName" DataValueField="CategoryID" 
            SelectedValue='<%# Bind("CategoryID") %>'>
        </asp:DropDownList>        
   </EditItemTemplate>
   <ItemTemplate>
       <asp:Label Runat="server" Text='<%# Bind("CategoryName") %>' 
          ID="Label1"></asp:Label>
   </ItemTemplate>
</asp:TemplateField>

この最後の追加では、DropDownList の SelectedValue='<%# Bind("CategoryID") %>を設定します。この例は完了です。 図 47 は、編集中の GridView のスクリーンショットを示しています。

ms972948.gridview_fg47(en-us,MSDN.10).gifms972948.gridview_fg47

図 47

次に、ASP.NET ページの完全な宣言構文を示します。 この演習全体は、コード行を記述せずに行われたことに注意してください。

<%@ Page Language="C#" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN" 
  "http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<script runat="server">
</script>
<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="productsDataSource" 
          Runat="server" SelectCommand="SELECT dbo.Products.ProductID, 
           dbo.Products.ProductName, dbo.Products.CategoryID, 
dbo.Categories.CategoryName FROM dbo.Products INNER JOIN dbo.Categories ON 
 dbo.Products.CategoryID = dbo.Categories.CategoryID"
            UpdateCommand="UPDATE [Products] SET [ProductName] = 
@ProductName, [CategoryID] = @CategoryID WHERE [ProductID] = 
@original_ProductID"
            ConnectionString="<%$ ConnectionStrings:NWConnectionString %>">
            <UpdateParameters>
                <asp:Parameter Type="String" 
                   Name="ProductName"></asp:Parameter>
                <asp:Parameter Type="Int32" Name="CategoryID"></asp:Parameter>
                <asp:Parameter Name="original_ProductID"></asp:Parameter>
            </UpdateParameters>
        </asp:SqlDataSource>
        <asp:SqlDataSource ID="categoryDataSource" Runat="server" 
           SelectCommand="SELECT [CategoryID], [CategoryName] FROM 
            [Categories] ORDER BY [CategoryName]"
            ConnectionString="<%$ ConnectionStrings:NWConnectionString %>">
        </asp:SqlDataSource>        
        <asp:GridView ID="GridView1" Runat="server" 
            DataSourceID="productsDataSource" DataKeyNames="ProductID"
            AutoGenerateColumns="False" AllowPaging="True" 
            BorderWidth="1px" BackColor="White"
            CellPadding="3" BorderStyle="None" BorderColor="#CCCCCC">
            <FooterStyle ForeColor="#000066" BackColor="White"></FooterStyle>
            <PagerStyle ForeColor="#000066" HorizontalAlign="Left" 
               BackColor="White"></PagerStyle>
            <HeaderStyle ForeColor="White" Font-Bold="True" 
               BackColor="#006699"></HeaderStyle>
            <Columns>
                <asp:CommandField ShowEditButton="True"></asp:CommandField>
                <asp:BoundField ReadOnly="True" HeaderText="ProductID" 
                  InsertVisible="False" DataField="ProductID"
                    SortExpression="ProductID">
                    <ItemStyle HorizontalAlign="Center"></ItemStyle>
                </asp:BoundField>
                <asp:BoundField HeaderText="ProductName" 
                  DataField="ProductName" 
                  SortExpression="ProductName"></asp:BoundField>
                <asp:TemplateField SortExpression="CategoryName" 
                    HeaderText="CategoryName"><EditItemTemplate>
                    <asp:DropDownList ID="DropDownList1" 
                          Runat="server" 
                          DataSourceID="categoryDataSource"
                        DataTextField="CategoryName" 
                   DataValueField="CategoryID" 
                     SelectedValue='<%# Bind("CategoryID") %>'>
                    </asp:DropDownList>                    
                </EditItemTemplate>
                    <ItemTemplate>
                        <asp:Label Runat="server" 
                       Text='<%# Bind("CategoryName") %>' 
                       ID="Label1"></asp:Label>
                    </ItemTemplate>
                </asp:TemplateField>
            </Columns>
            <SelectedRowStyle ForeColor="White" 
                Font-Bold="True" BackColor="#669999"></SelectedRowStyle>
            <RowStyle ForeColor="#000066"></RowStyle>
        </asp:GridView>
    
    </div>
    </form>
</body>
</html>

© Microsoft Corporation. All rights reserved.