次の方法で共有


GridView のフッターから新しいレコードを挿入する (VB)

スコット・ミッチェル著

PDF をダウンロードする

GridView コントロールでは、データの新しいレコードを挿入するための組み込みのサポートは提供されませんが、このチュートリアルでは、挿入インターフェイスを含むように GridView を拡張する方法を示します。

イントロダクション

「データの挿入、更新、および削除の概要」チュートリアルで説明したように、GridView、DetailsView、および FormView Web コントロールには、それぞれ組み込みのデータ変更機能が含まれています。 宣言型データ ソース コントロールと共に使用する場合、これら 3 つの Web コントロールは、1 行のコードを記述しなくても、データを変更するように迅速かつ簡単に構成できます。 残念ながら、組み込みの挿入、編集、および削除機能を提供するのは DetailsView コントロールと FormView コントロールだけです。 GridView では、編集と削除のサポートのみが提供されます。 しかし、少しの努力で、挿入インターフェイスを含むように GridView を拡張できます。

GridView に挿入機能を追加する場合、新しいレコードの追加方法を決定し、挿入インターフェイスを作成し、新しいレコードを挿入するコードを記述する必要があります。 このチュートリアルでは、挿入インターフェイスを GridView のフッター行に追加する方法について説明します (図 1 を参照)。 各列のフッター セルには、適切なデータ コレクションのユーザー インターフェイス要素 (製品名の TextBox、サプライヤーの DropDownList など) が含まれます。 また、[追加] ボタンの列も必要です。このボタンをクリックするとポストバックが発生し、フッター行に指定された値を使用して Products テーブルに新しいレコードが挿入されます。

[フッター] 行には、新しい製品を追加するためのインターフェイスが用意されています

図 1: フッター行は、新しい製品を追加するためのインターフェイスを提供します (フルサイズの画像を表示する をクリックします)。

手順 1: GridView で製品情報を表示する

GridView のフッターに挿入インターフェイスを作成する前に、まず、データベース内の製品を一覧表示するページに GridView を追加することに焦点を当ててみましょう。 まず、InsertThroughFooter.aspx フォルダーのEnhancedGridView ページを開き、ツールボックスからデザイナーに GridView をドラッグし、GridView の ID プロパティをProductsに設定します。 次に、GridView のスマート タグを使用して、 ProductsDataSourceという名前の新しい ObjectDataSource にバインドします。

ProductsDataSource という名前の新しい ObjectDataSource を作成する

図 2: 名前付きの新しい ObjectDataSource ProductsDataSource を作成する (フルサイズの画像を表示する をクリックします)

ProductsBLL クラスの GetProducts() メソッドを使用して製品情報を取得するように ObjectDataSource を構成します。 このチュートリアルでは、挿入機能の追加に重点を置き、編集や削除について心配しないようにしましょう。 そのため、[INSERT] タブのドロップダウン リストが AddProduct() に設定されていること、および [UPDATE] タブと [DELETE] タブのドロップダウン リストが [なし] に設定されていることを確認します。

AddProduct メソッドを ObjectDataSource s Insert() メソッドにマップする

図 3: AddProduct メソッドを ObjectDataSource の Insert() メソッドにマップします (フルサイズの画像を表示する をクリックします)。

UPDATE タブと DELETE タブ Drop-Down リストを (なし) に設定する

図 4: [UPDATE] タブと [DELETE] タブ Drop-Down リストを [なし] に設定する (フルサイズの画像を表示する 場合はクリックします)

ObjectDataSource のデータ ソースの構成ウィザードが完了すると、Visual Studio によって、対応する各データ フィールドのフィールドが GridView に自動的に追加されます。 ここでは、Visual Studio によって追加されたすべてのフィールドをそのまま使用します。 このチュートリアルの後半では、新しいレコードを追加するときに値を指定する必要がないフィールドの一部を元に戻して削除します。

データベースには 80 個に近い製品があるため、ユーザーは Web ページの下部までスクロールして新しいレコードを追加する必要があります。 そのため、ページングを有効にして、挿入インターフェイスをより見え、アクセスしやすくします。 ページングを有効にするには、GridView のスマート タグの [ページングを有効にする] チェック ボックスをオンにします。

この時点で、GridView と ObjectDataSource の宣言型マークアップは次のようになります。

<asp:GridView ID="Products" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="ProductID" DataSourceID="ProductsDataSource" 
    AllowPaging="True" EnableViewState="False">
    <Columns>
        <asp:BoundField DataField="ProductID" HeaderText="ProductID" 
            InsertVisible="False" ReadOnly="True" 
            SortExpression="ProductID" />
        <asp:BoundField DataField="ProductName" HeaderText="ProductName" 
            SortExpression="ProductName" />
        <asp:BoundField DataField="SupplierID" HeaderText="SupplierID" 
            SortExpression="SupplierID" />
        <asp:BoundField DataField="CategoryID" HeaderText="CategoryID" 
            SortExpression="CategoryID" />
        <asp:BoundField DataField="QuantityPerUnit" HeaderText="QuantityPerUnit" 
            SortExpression="QuantityPerUnit" />
        <asp:BoundField DataField="UnitPrice" HeaderText="UnitPrice" 
            SortExpression="UnitPrice" />
        <asp:BoundField DataField="UnitsInStock" HeaderText="UnitsInStock" 
            SortExpression="UnitsInStock" />
        <asp:BoundField DataField="UnitsOnOrder" HeaderText="UnitsOnOrder" 
            SortExpression="UnitsOnOrder" />
        <asp:BoundField DataField="ReorderLevel" HeaderText="ReorderLevel" 
            SortExpression="ReorderLevel" />
        <asp:CheckBoxField DataField="Discontinued" HeaderText="Discontinued" 
            SortExpression="Discontinued" />
        <asp:BoundField DataField="CategoryName" HeaderText="CategoryName" 
            ReadOnly="True" SortExpression="CategoryName" />
        <asp:BoundField DataField="SupplierName" HeaderText="SupplierName" 
            ReadOnly="True" SortExpression="SupplierName" />
    </Columns>
</asp:GridView>
<asp:ObjectDataSource ID="ProductsDataSource" runat="server" 
    InsertMethod="AddProduct" OldValuesParameterFormatString="original_{0}" 
    SelectMethod="GetProducts" TypeName="ProductsBLL">
    <InsertParameters>
        <asp:Parameter Name="productName" Type="String" />
        <asp:Parameter Name="supplierID" Type="Int32" />
        <asp:Parameter Name="categoryID" Type="Int32" />
        <asp:Parameter Name="quantityPerUnit" Type="String" />
        <asp:Parameter Name="unitPrice" Type="Decimal" />
        <asp:Parameter Name="unitsInStock" Type="Int16" />
        <asp:Parameter Name="unitsOnOrder" Type="Int16" />
        <asp:Parameter Name="reorderLevel" Type="Int16" />
        <asp:Parameter Name="discontinued" Type="Boolean" />
    </InsertParameters>
</asp:ObjectDataSource>

すべての製品データ フィールドが Paged GridView に表示される

図 5: すべての製品データ フィールドが Paged GridView に表示されます (フルサイズの画像を表示する をクリックします)。

GridView には、ヘッダー行とデータ行に加えて、フッター行が含まれます。 ヘッダーとフッターの行は、GridView の ShowHeader プロパティと ShowFooter プロパティの値に応じて表示されます。 フッター行を表示するには、 ShowFooter プロパティを True に設定するだけです。 図 6 に示すように、 ShowFooter プロパティを True に設定すると、フッター行がグリッドに追加されます。

フッター行を表示するには、ShowFooter を True に設定します。

図 6: フッター行を表示するには、 ShowFooterTrue に設定します (フルサイズの画像を表示する をクリックします)。

フッター行の背景色は濃い赤色であることに注意してください。 これは、 ObjectDataSource を使用したデータの表示に関するチュートリアルで作成し、すべてのページに適用した DataWebControls テーマが原因です。 具体的には、GridView.skin ファイルは、FooterStyle CSS クラスを使用するようにFooterStyle プロパティを構成します。 FooterStyle クラスは、Styles.cssで次のように定義されます。

.FooterStyle
{
    background-color: #a33;
    color: White;
    text-align: right;
}

前のチュートリアルでは、GridView のフッター行を使用して調べてきました。 必要に応じて、 GridView のフッターに概要情報を表示する チュートリアルに戻って、更新プログラムを参照してください。

ShowFooter プロパティを True に設定した後、しばらくしてブラウザーで出力を表示します。 現在、フッター行にはテキストまたは Web コントロールは含まれません。 手順 3 では、適切な挿入インターフェイスが含まれるように、各 GridView フィールドのフッターを変更します。

空のフッター行はページング インターフェイス コントロールの上に表示されます

図 7: 空のフッター行がページング インターフェイス コントロールの上に表示されます (フルサイズの画像を表示する をクリックします)。

GridView コントロールのチュートリアルの TemplateFields の使用に戻り、(BoundFields や CheckBoxFields ではなく) TemplateFields を使用して特定の GridView 列の表示を大幅にカスタマイズする方法について説明しました。「データ変更インターフェイスのカスタマイズ」で、TemplateFields を使用して GridView の編集インターフェイスをカスタマイズする方法について説明しました。 TemplateField は、特定の種類の行に使用されるマークアップ、Web コントロール、およびデータ バインド構文の組み合わせを定義する多数のテンプレートで構成されていることを思い出してください。 たとえば、 ItemTemplateは読み取り専用行に使用されるテンプレートを指定しますが、 EditItemTemplate では編集可能な行のテンプレートが定義されます。

ItemTemplateEditItemTemplateに加えて、TemplateField にはフッター行の内容を指定するFooterTemplateも含まれています。 そのため、インターフェイスを挿入する各フィールドに必要な Web コントロールを FooterTemplateに追加できます。 開始するには、GridView 内のすべてのフィールドを TemplateFields に変換します。 これを行うには、GridView のスマート タグの [列の編集] リンクをクリックし、左下隅の各フィールドを選択し、[このフィールドを TemplateField に変換] リンクをクリックします。

各フィールドを TemplateField に変換する

図 8: 各フィールドを TemplateField に変換する

[このフィールドを TemplateField に変換] をクリックすると、現在のフィールド型が同等の TemplateField に変換されます。 たとえば、各 BoundField は TemplateField に置き換えられ、対応するデータ フィールドを表示するラベルと、テキスト ボックスにデータ フィールドを表示するItemTemplateを含むEditItemTemplateに置き換えられます。 ProductName BoundField は、次の TemplateField マークアップに変換されています。

<asp:TemplateField HeaderText="ProductName" SortExpression="ProductName">
    <EditItemTemplate>
        <asp:TextBox ID="TextBox1" runat="server" 
            Text='<%# Bind("ProductName") %>'></asp:TextBox>
    </EditItemTemplate>
    <ItemTemplate>
        <asp:Label ID="Label2" runat="server" 
            Text='<%# Bind("ProductName") %>'></asp:Label>
    </ItemTemplate>
</asp:TemplateField>

同様に、 Discontinued CheckBoxField は TemplateField に変換され、その ItemTemplateEditItemTemplate には CheckBox Web コントロールが含まれています ( ItemTemplate の CheckBox が無効になっています)。 読み取り専用 ProductID BoundField は、 ItemTemplateEditItemTemplateの両方で Label コントロールを持つ TemplateField に変換されています。 つまり、既存の GridView フィールドを TemplateField に変換すると、既存のフィールドの機能を失うことなく、よりカスタマイズ可能な TemplateField にすばやく簡単に切り替えることができます。

作業中の GridView では編集がサポートされていないため、各 TemplateField から EditItemTemplate を削除して、 ItemTemplateだけを残してください。 これを行った後、GridView の宣言型マークアップは次のようになります。

<asp:GridView ID="Products" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="ProductID" DataSourceID="ProductsDataSource" 
    AllowPaging="True" EnableViewState="False" ShowFooter="True">
    <Columns>
        <asp:TemplateField HeaderText="ProductID" InsertVisible="False" 
            SortExpression="ProductID">
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" 
                    Text='<%# Bind("ProductID") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="ProductName" SortExpression="ProductName">
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server" 
                    Text='<%# Bind("ProductName") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="SupplierID" SortExpression="SupplierID">
            <ItemTemplate>
                <asp:Label ID="Label3" runat="server" 
                    Text='<%# Bind("SupplierID") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="CategoryID" SortExpression="CategoryID">
            <ItemTemplate>
                <asp:Label ID="Label4" runat="server" 
                    Text='<%# Bind("CategoryID") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="QuantityPerUnit" 
            SortExpression="QuantityPerUnit">
            <ItemTemplate>
                <asp:Label ID="Label5" runat="server" 
                    Text='<%# Bind("QuantityPerUnit") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="UnitPrice" SortExpression="UnitPrice">
            <ItemTemplate>
                <asp:Label ID="Label6" runat="server" 
                    Text='<%# Bind("UnitPrice") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="UnitsInStock" 
            SortExpression="UnitsInStock">
            <ItemTemplate>
                <asp:Label ID="Label7" runat="server" 
                    Text='<%# Bind("UnitsInStock") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="UnitsOnOrder" 
            SortExpression="UnitsOnOrder">
            <ItemTemplate>
                <asp:Label ID="Label8" runat="server" 
                    Text='<%# Bind("UnitsOnOrder") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="ReorderLevel" 
            SortExpression="ReorderLevel">
            <ItemTemplate>
                <asp:Label ID="Label9" runat="server" 
                    Text='<%# Bind("ReorderLevel") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Discontinued" 
            SortExpression="Discontinued">
            <ItemTemplate>
                <asp:CheckBox ID="CheckBox1" runat="server" 
                    Checked='<%# Bind("Discontinued") %>' Enabled="false" />
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="CategoryName" 
            SortExpression="CategoryName">
            <ItemTemplate>
                <asp:Label ID="Label10" runat="server" 
                    Text='<%# Bind("CategoryName") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="SupplierName" 
            SortExpression="SupplierName">
            <ItemTemplate>
                <asp:Label ID="Label11" runat="server" 
                    Text='<%# Bind("SupplierName") %>'></asp:Label>
            </ItemTemplate>
        </asp:TemplateField>
    </Columns>
</asp:GridView>

各 GridView フィールドが TemplateField に変換されたので、各フィールドの FooterTemplateに適切な挿入インターフェイスを入力できます。 一部のフィールドには挿入インターフェイス (ProductIDなど) がありません。その他のフィールドは、新しい製品の情報を収集するために使用される Web コントロールによって異なります。

編集インターフェイスを作成するには、GridView のスマート タグから [テンプレートの編集] リンクを選択します。 次に、ドロップダウン リストから適切なフィールドの FooterTemplate を選択し、ツールボックスからデザイナーに適切なコントロールをドラッグします。

各フィールドの FooterTemplate に適切な挿入インターフェイスを追加する

図 9: 各フィールドの FooterTemplate に適切な挿入インターフェイスを追加します (フルサイズの画像を表示する をクリックします)。

次の箇条書きでは、追加する挿入インターフェイスを指定して、GridView フィールドを列挙します。

  • ProductID なし。
  • ProductName テキスト ボックスを追加し、その IDNewProductNameに設定します。 RequiredFieldValidator コントロールを追加して、ユーザーが新しい製品名の値を入力するようにします。
  • SupplierID なし。
  • CategoryID なし。
  • QuantityPerUnit テキスト ボックスを追加し、その IDNewQuantityPerUnitに設定します。
  • UnitPrice NewUnitPriceという名前の TextBox と、入力した値が 0 以上の通貨値であることを確認する CompareValidator を追加します。
  • UnitsInStock IDNewUnitsInStock に設定されている TextBox を使用します。 入力した値が 0 以上の整数値であることを保証する CompareValidator を含めます。
  • UnitsOnOrder IDNewUnitsOnOrder に設定されている TextBox を使用します。 入力した値が 0 以上の整数値であることを保証する CompareValidator を含めます。
  • ReorderLevel IDNewReorderLevel に設定されている TextBox を使用します。 入力した値が 0 以上の整数値であることを保証する CompareValidator を含めます。
  • Discontinued CheckBox を追加し、その IDNewDiscontinuedに設定します。
  • CategoryName DropDownList を追加し、その IDNewCategoryIDに設定します。 CategoriesDataSourceという名前の新しい ObjectDataSource にバインドし、CategoriesBLL クラスの GetCategories() メソッドを使用するように構成します。 DropDownList ListItemCategoryName データ フィールドを表示し、CategoryID データ フィールドを値として使用します。
  • SupplierName DropDownList を追加し、その IDNewSupplierIDに設定します。 SuppliersDataSourceという名前の新しい ObjectDataSource にバインドし、SuppliersBLL クラスの GetSuppliers() メソッドを使用するように構成します。 DropDownList ListItemCompanyName データ フィールドを表示し、SupplierID データ フィールドを値として使用します。

検証コントロールごとに、 ForeColor プロパティをクリアして、 FooterStyle CSS クラスの白い前景色が既定の赤の代わりに使用されるようにします。 また、詳細な説明には ErrorMessage プロパティを使用しますが、 Text プロパティをアスタリスクに設定します。 検証コントロールのテキストによって挿入インターフェイスが 2 行に折り返されないようにするには、検証コントロールを使用する各FooterStyleに対して、WrapFooterTemplate プロパティを false に設定します。 最後に、GridView の下に ValidationSummary コントロールを追加し、その ShowMessageBox プロパティを True に設定し、その ShowSummary プロパティを False に設定します。

新しい製品を追加するときは、 CategoryIDSupplierIDを提供する必要があります。 この情報は、 CategoryName フィールドと SupplierName フィールドのフッター セルの DropDownLists を介してキャプチャされます。 グリッドのデータ行では、ユーザーが ID 値ではなくカテゴリ名とサプライヤー名を表示することに関心がある可能性が高いため、 CategoryIDSupplierID TemplateFields ではなく、これらのフィールドを使用することを選択しました。 CategoryIDSupplierIDの値は、CategoryNameおよびSupplierNameフィールドの挿入インターフェイスにキャプチャされるため、GridView から CategoryID および SupplierID TemplateFields を削除できます。

同様に、 ProductID は新しい製品を追加するときに使用されないため、 ProductID TemplateField も削除できます。 ただし、グリッドの [ ProductID ] フィールドはそのままにしておきます。 挿入インターフェイスを構成する TextBoxes、DropDownLists、CheckBoxes、検証コントロールに加えて、[追加] ボタンも必要です。このボタンをクリックすると、新しい製品をデータベースに追加するロジックが実行されます。 手順 4 では、 ProductID TemplateField の FooterTemplateの挿入インターフェイスに [追加] ボタンを含めます。

さまざまな GridView フィールドの外観を自由に改善してください。 たとえば、 UnitPrice 値を通貨として書式設定し、 UnitsInStockUnitsOnOrder、および ReorderLevel フィールドを右揃えし、TemplateFields の HeaderText 値を更新することができます。

FooterTemplateで多数のインターフェイスを挿入し、SupplierIDを削除し、TemplateFields の書式設定と配置によって美観を整えることにより、GridView の宣言型マークアップは次のようになります。

<asp:GridView ID="Products" runat="server" AutoGenerateColumns="False" 
    DataKeyNames="ProductID" DataSourceID="ProductsDataSource" 
    AllowPaging="True" EnableViewState="False" ShowFooter="True">
    <Columns>
        <asp:TemplateField HeaderText="ProductID" InsertVisible="False" 
            SortExpression="ProductID">
            <ItemTemplate>
                <asp:Label ID="Label1" runat="server" 
                    Text='<%# Bind("ProductID") %>'></asp:Label>
            </ItemTemplate>
            <ItemStyle HorizontalAlign="Center" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Product" SortExpression="ProductName">
            <ItemTemplate>
                <asp:Label ID="Label2" runat="server" 
                    Text='<%# Bind("ProductName") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:TextBox ID="NewProductName" runat="server"></asp:TextBox>
                <asp:RequiredFieldValidator ID="RequiredFieldValidator1" 
                    runat="server" ControlToValidate="NewProductName"
                    Display="Dynamic"  ForeColor="
                    ErrorMessage="You must enter a name for the new product.">
                    * </asp:RequiredFieldValidator>
            </FooterTemplate>
            <FooterStyle Wrap="False" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Category" SortExpression="CategoryName">
            <ItemTemplate>
                <asp:Label ID="Label10" runat="server" 
                    Text='<%# Bind("CategoryName") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:DropDownList ID="NewCategoryID" runat="server" 
                    DataSourceID="CategoriesDataSource"
                    DataTextField="CategoryName" DataValueField="CategoryID">
                </asp:DropDownList>
                <asp:ObjectDataSource ID="CategoriesDataSource" runat="server"
                    OldValuesParameterFormatString="original_{0}" 
                    SelectMethod="GetCategories" TypeName="CategoriesBLL">
                </asp:ObjectDataSource>
            </FooterTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Supplier" SortExpression="SupplierName">
            <ItemTemplate>
                <asp:Label ID="Label11" runat="server" 
                    Text='<%# Bind("SupplierName") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:DropDownList ID="NewSupplierID" runat="server" 
                    DataSourceID="SuppliersDataSource"
                    DataTextField="CompanyName" DataValueField="SupplierID">
                </asp:DropDownList><asp:ObjectDataSource ID="SuppliersDataSource" 
                    runat="server" OldValuesParameterFormatString="original_{0}" 
                    SelectMethod="GetSuppliers" TypeName="SuppliersBLL">
                </asp:ObjectDataSource>
            </FooterTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Qty/Unit" SortExpression="QuantityPerUnit">
            <ItemTemplate>
                <asp:Label ID="Label5" runat="server" 
                    Text='<%# Bind("QuantityPerUnit") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:TextBox ID="NewQuantityPerUnit" runat="server"></asp:TextBox>
            </FooterTemplate>
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Price" SortExpression="UnitPrice">
            <ItemTemplate>
                <asp:Label ID="Label6" runat="server" 
                    Text='<%# Bind("UnitPrice", "{0:c}") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                $<asp:TextBox ID="NewUnitPrice" runat="server" Columns="8" />
                <asp:CompareValidator ID="CompareValidator1" runat="server" 
                    ControlToValidate="NewUnitPrice"
                    ErrorMessage="You must enter a valid currency value greater than 
                        or equal to 0.00. Do not include the currency symbol."
                    ForeColor="" Operator="GreaterThanEqual" Type="Currency" 
                    ValueToCompare="0" Display="Dynamic">
                    * </asp:CompareValidator>
            </FooterTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <FooterStyle Wrap="False" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Units In Stock" 
            SortExpression="Units In Stock">
            <ItemTemplate>
                <asp:Label ID="Label7" runat="server" 
                    Text='<%# Bind("UnitsInStock") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:TextBox ID="NewUnitsInStock" runat="server" Columns="5" />
                <asp:CompareValidator ID="CompareValidator2" runat="server" 
                    ControlToValidate="NewUnitsInStock" Display="Dynamic" 
                    ErrorMessage="You must enter a valid numeric value for units 
                        in stock that's greater than or equal to zero."
                    ForeColor="" Operator="GreaterThanEqual" Type="Integer" 
                        ValueToCompare="0">*</asp:CompareValidator>
            </FooterTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <FooterStyle Wrap="False" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Units On Order" SortExpression="UnitsOnOrder">
            <ItemTemplate>
                <asp:Label ID="Label8" runat="server" 
                    Text='<%# Bind("UnitsOnOrder") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:TextBox ID="NewUnitsOnOrder" runat="server" Columns="5" />
                <asp:CompareValidator ID="CompareValidator3" runat="server" 
                    ControlToValidate="NewUnitsOnOrder" Display="Dynamic" 
                    ErrorMessage="You must enter a valid numeric value for units on 
                        order that's greater than or equal to zero."
                    ForeColor="" Operator="GreaterThanEqual" Type="Integer" 
                    ValueToCompare="0">*</asp:CompareValidator>
            </FooterTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <FooterStyle Wrap="False" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Reorder Level" SortExpression="ReorderLevel">
            <ItemTemplate>
                <asp:Label ID="Label9" runat="server" 
                    Text='<%# Bind("ReorderLevel") %>'></asp:Label>
            </ItemTemplate>
            <FooterTemplate>
                <asp:TextBox ID="NewReorderLevel" runat="server" Columns="5" />
                <asp:CompareValidator ID="CompareValidator4" runat="server" 
                    ControlToValidate="NewReorderLevel" Display="Dynamic" 
                    ErrorMessage="You must enter a valid numeric value for reorder 
                        level that's greater than or equal to zero."
                    ForeColor="" Operator="GreaterThanEqual" Type="Integer" 
                    ValueToCompare="0">*</asp:CompareValidator>
            </FooterTemplate>
            <ItemStyle HorizontalAlign="Right" />
            <FooterStyle Wrap="False" />
        </asp:TemplateField>
        <asp:TemplateField HeaderText="Discontinued" SortExpression="Discontinued">
            <ItemTemplate>
                <asp:CheckBox ID="CheckBox1" runat="server" 
                    Checked='<%# Bind("Discontinued") %>' Enabled="false" />
            </ItemTemplate>
            <FooterTemplate>
                <asp:CheckBox ID="NewDiscontinued" runat="server" />
            </FooterTemplate>
            <ItemStyle HorizontalAlign="Center" />
            <FooterStyle HorizontalAlign="Center" />
        </asp:TemplateField>
    </Columns>
</asp:GridView>

ブラウザーで表示すると、GridView のフッター行に、完成した挿入インターフェイスが含まれるようになりました (図 10 を参照)。 この時点で、挿入インターフェイスには、ユーザーが新しい製品のデータを入力し、データベースに新しいレコードを挿入することを示す手段は含まれません。 また、フッターに入力されたデータが Products データベースの新しいレコードにどのように変換されるかについては、まだ説明していません。 手順 4 では、挿入インターフェイスに [追加] ボタンを含める方法と、ポストバックがクリックされたときにコードを実行する方法について説明します。 手順 5 では、フッターのデータを使用して新しいレコードを挿入する方法を示します。

GridView フッターには、新しいレコードを追加するためのインターフェイスが用意されています

図 10: GridView フッターは、新しいレコードを追加するためのインターフェイスを提供します (フルサイズの画像を表示する をクリックします)。

手順 4: 挿入インターフェイスに追加ボタンを含める

フッター行の挿入インターフェイスには現在、ユーザーが新製品の情報の入力を完了したことを示す手段がないため、挿入インターフェイスのどこかに [追加] ボタンを含める必要があります。 これは、既存の FooterTemplate のいずれかに配置することも、この目的のためにグリッドに新しい列を追加することもできます。 このチュートリアルでは、 ProductID TemplateField の FooterTemplateに [追加] ボタンを配置します。

デザイナーで、GridView のスマート タグの [テンプレートの編集] リンクをクリックし、ドロップダウン リストからProductIDFooterTemplate フィールドを選択します。 図 11 に示すように、テンプレートに Button Web コントロール (または必要に応じて LinkButton または ImageButton) を追加し、その ID を AddProduct に設定し、その CommandName を Insert に、 Text プロパティを Add に設定します。

ProductID TemplateField の FooterTemplate に [追加] ボタンを配置する

図 11: ProductID TemplateField の FooterTemplate に [追加] ボタンを配置する (フルサイズの画像を表示する をクリックします)

[追加] ボタンを含めたら、ブラウザーでページをテストします。 挿入インターフェイスで無効なデータを含む [追加] ボタンをクリックすると、ポストバックがショートし、ValidationSummary コントロールが無効なデータを示します (図 12 を参照)。 適切なデータを入力すると、[追加] ボタンをクリックするとポストバックが発生します。 ただし、データベースにはレコードは追加されません。 実際に挿入を実行するには、少しコードを記述する必要があります。

挿入インターフェイスに無効なデータがある場合、追加ボタンのポストバックが遮断される

図 12: 挿入インターフェイスに無効なデータがある場合、[追加ボタン] のポストバックはショートサーキットされます (フルサイズの画像を表示するにはクリックします)

挿入インターフェイスの検証コントロールが検証グループに割り当てされませんでした。 これは、挿入インターフェイスがページ上の検証コントロールの唯一のセットである限り、正常に動作します。 ただし、ページに他の検証コントロール (グリッドの編集インターフェイスの検証コントロールなど) がある場合は、挿入インターフェイスの検証コントロールと [追加] ボタンの ValidationGroup プロパティに、これらのコントロールを特定の検証グループに関連付けるために同じ値を割り当てる必要があります。 ページ上 の検証コントロールとボタンを検証グループに分割する 方法の詳細については、ASP.NET 2.0 の検証コントロールの分割に関するページを参照してください。

手順 5: ProductsTable に新しいレコードを挿入する

GridView の組み込みの編集機能を利用すると、GridView は更新の実行に必要なすべての作業を自動的に処理します。 特に、[更新] ボタンをクリックすると、編集インターフェイスから入力された値が ObjectDataSource の UpdateParameters コレクション内のパラメーターにコピーされ、ObjectDataSource の Update() メソッドを呼び出して更新が開始されます。 GridView にはこのような挿入用の組み込み機能がないため、ObjectDataSource の Insert() メソッドを呼び出し、挿入インターフェイスから ObjectDataSource の InsertParameters コレクションに値をコピーするコードを実装する必要があります。

この挿入ロジックは、[追加] ボタンがクリックされた後に実行する必要があります。 GridView のボタンの追加と応答チュートリアルで説明したように、GridView の Button、LinkButton、または ImageButton がクリックされるたびに、GridView のRowCommandイベントはポストバック時に発生します。 このイベントは、フッター行の [追加] ボタンなど、Button、LinkButton、ImageButton が明示的に追加されたか、GridView によって自動的に追加されたか ([並べ替えを有効にする] が選択されている場合は各列の上部にある LinkButtons、ページングを有効にする] が選択されている場合はページング インターフェイスの LinkButtons など) に対して発生します。

そのため、[追加] ボタンをクリックしてユーザーに応答するには、GridView の RowCommand イベントのイベント ハンドラーを作成する必要があります。 このイベントは、GridView の Button、 LinkButton、または ImageButton がクリックされるたびに発生するため、イベント ハンドラーに渡された CommandName プロパティが [追加] ボタン (挿入) の CommandName 値にマップされている場合にのみ、挿入ロジックを続行することが重要です。 さらに、検証コントロールが有効なデータを報告する場合にのみ、続行する必要があります。 これに対応するには、次のコードを使用して、 RowCommand イベントのイベント ハンドラーを作成します。

Protected Sub Products_RowCommand(sender As Object, e As GridViewCommandEventArgs) _
    Handles Products.RowCommand
    
    ' Insert data if the CommandName == "Insert" 
    ' and the validation controls indicate valid data...
    If e.CommandName = "Insert" AndAlso Page.IsValid Then
        ' TODO: Insert new record...
    End If
End Sub

イベント ハンドラーがなぜ Page.IsValid プロパティのチェックを気にするのか疑問に思うかもしれません。 結局のところ、挿入インターフェイスで無効なデータが提供されている場合、ポストバックは抑制されませんか? ユーザーが JavaScript を無効にしていないか、クライアント側の検証ロジックを回避する手順を実行している限り、この前提は正しいです。 つまり、クライアント側の検証に厳密に依存しないでください。データを操作する前に、サーバー側の有効性チェックを常に実行する必要があります。

手順 1 では、ProductsDataSource メソッドが Insert() クラスの ProductsBLL メソッドにマップされるように、AddProduct ObjectDataSource を作成しました。 Products テーブルに新しいレコードを挿入するには、ObjectDataSource の Insert() メソッドを呼び出します。

Protected Sub Products_RowCommand(sender As Object, e As GridViewCommandEventArgs) _
    Handles Products.RowCommand
    
    ' Insert data if the CommandName == "Insert" 
    ' and the validation controls indicate valid data...
    If e.CommandName = "Insert" AndAlso Page.IsValid Then
        ' Insert new record
        ProductsDataSource.Insert()
    End If
End Sub

Insert() メソッドが呼び出されたので、残っているのは、挿入インターフェイスの値を、ProductsBLL クラスの AddProduct メソッドに渡されたパラメーターにコピーすることにあります。 挿入 、更新、および削除に関連するイベントの確認に関する チュートリアルで説明したように、これは ObjectDataSource の Inserting イベントを使用して実現できます。 Inserting イベントでは、プログラムによって Products GridView のフッター行からコントロールを参照し、その値を e.InputParameters コレクションに割り当てる必要があります。 ReorderLevel TextBox を空白のままにするなど、ユーザーが値を省略した場合は、データベースに挿入される値をNULLするように指定する必要があります。 AddProductsメソッドは null 許容データベース フィールドに対して null 許容型を受け入れるので、単に null 許容型を使用し、ユーザー入力を省略した場合は値をNothingに設定します。

Protected Sub ProductsDataSource_Inserting _
    (sender As Object, e As .ObjectDataSourceMethodEventArgs) _
    Handles ProductsDataSource.Inserting
    
    ' Programmatically reference Web controls in the inserting interface...
    Dim NewProductName As TextBox = _
        Products.FooterRow.FindControl("NewProductName")
    Dim NewCategoryID As DropDownList = _
        Products.FooterRow.FindControl("NewCategoryID")
    Dim NewSupplierID As DropDownList = _
        Products.FooterRow.FindControl("NewSupplierID")
    Dim NewQuantityPerUnit As TextBox = _
        Products.FooterRow.FindControl("NewQuantityPerUnit")
    Dim NewUnitPrice As TextBox = _
        Products.FooterRow.FindControl("NewUnitPrice")
    Dim NewUnitsInStock As TextBox = _
        Products.FooterRow.FindControl("NewUnitsInStock")
    Dim NewUnitsOnOrder As TextBox = _
        Products.FooterRow.FindControl("NewUnitsOnOrder")
    Dim NewReorderLevel As TextBox = _
        Products.FooterRow.FindControl("NewReorderLevel")
    Dim NewDiscontinued As CheckBox = _
        Products.FooterRow.FindControl("NewDiscontinued")
    ' Set the ObjectDataSource's InsertParameters values...
    e.InputParameters("productName") = NewProductName.Text
    e.InputParameters("supplierID") = _
        Convert.ToInt32(NewSupplierID.SelectedValue)
    e.InputParameters("categoryID") = _
        Convert.ToInt32(NewCategoryID.SelectedValue)
    Dim quantityPerUnit As String = Nothing
    If Not String.IsNullOrEmpty(NewQuantityPerUnit.Text) Then
        quantityPerUnit = NewQuantityPerUnit.Text
    End If
    e.InputParameters("quantityPerUnit") = quantityPerUnit
    Dim unitPrice As Nullable(Of Decimal) = Nothing
    If Not String.IsNullOrEmpty(NewUnitPrice.Text) Then
        unitPrice = Convert.ToDecimal(NewUnitPrice.Text)
    End If
    e.InputParameters("unitPrice") = unitPrice
    Dim unitsInStock As Nullable(Of Short) = Nothing
    If Not String.IsNullOrEmpty(NewUnitsInStock.Text) Then
        unitsInStock = Convert.ToInt16(NewUnitsInStock.Text)
    End If
    e.InputParameters("unitsInStock") = unitsInStock
    Dim unitsOnOrder As Nullable(Of Short) = Nothing
    If Not String.IsNullOrEmpty(NewUnitsOnOrder.Text) Then
        unitsOnOrder = Convert.ToInt16(NewUnitsOnOrder.Text)
    End If
    e.InputParameters("unitsOnOrder") = unitsOnOrder
    Dim reorderLevel As Nullable(Of Short) = Nothing
    If Not String.IsNullOrEmpty(NewReorderLevel.Text) Then
        reorderLevel = Convert.ToInt16(NewReorderLevel.Text)
    End If
    e.InputParameters("reorderLevel") = reorderLevel
    e.InputParameters("discontinued") = NewDiscontinued.Checked
End Sub

Inserting イベント ハンドラーが完了したら、GridView のフッター行を使用して、Products データベース テーブルに新しいレコードを追加できます。 先に進み、いくつかの新しい製品を追加してみてください。

追加操作の拡張とカスタマイズ

現時点では、[追加] ボタンをクリックすると、データベース テーブルに新しいレコードが追加されますが、レコードが正常に追加されたことを示す視覚的なフィードバックは提供されません。 ラベル Web コントロールまたはクライアント側のアラート ボックスは、挿入が正常に完了したことをユーザーに通知するのが理想的です。 私はこれを読者の練習として残します。

このチュートリアルで使用する GridView は、リストされている製品に並べ替え順序を適用したり、エンド ユーザーがデータを並べ替えたりすることはありません。 その結果、レコードはデータベース内の主キー フィールドによって並べ替えられます。 各新しいレコードには最後のレコードより大きい ProductID 値があるため、新しい製品が追加されるたびにグリッドの末尾に取り付けられます。 そのため、新しいレコードを追加した後、GridView の最後のページにユーザーを自動的に送信することができます。 これを実現するには、ProductsDataSource.Insert() イベント ハンドラーでRowCommandの呼び出しの後に次のコード行を追加して、データを GridView にバインドした後、ユーザーを最後のページに送信する必要があることを示します。

' Indicate that the user needs to be sent to the last page
SendUserToLastPage = True

SendUserToLastPage は、最初に False の値が割り当てられたページ レベルのブール変数です。 GridView DataBound イベント ハンドラーで、 SendUserToLastPage が false の場合、 PageIndex プロパティが更新され、ユーザーが最後のページに送信されます。

Protected Sub Products_DataBound(sender As Object, e As EventArgs) _
    Handles Products.DataBound
    
    ' Send user to last page of data, if needed
    If SendUserToLastPage Then
        Products.PageIndex = Products.PageCount - 1
    End If
End Sub

PageIndex プロパティが (DataBound イベント ハンドラーではなく) RowCommand イベント ハンドラーで設定されるのは、RowCommand イベント ハンドラーが起動したときに、Products データベース テーブルに新しいレコードをまだ追加していないためです。 したがって、 RowCommand イベント ハンドラーでは、最後のページ インデックス (PageCount - 1) は、新しい製品が追加される の最後のページ インデックスを表します。 追加される製品の大部分では、新しい製品を追加した後の最後のページ インデックスは同じです。 ただし、追加された製品で新しい最後のページ インデックスが作成された場合、PageIndex イベント ハンドラーでRowCommandを誤って更新すると、新しい最後のページ インデックスではなく、最後から2番目のページ (新しい製品を追加する前の最後のページ インデックス) に移動します。 DataBound イベント ハンドラーは、新しい製品が追加され、データがグリッドにリバインドされた後に発生するため、PageIndex プロパティを設定することで、正しい最後のページ インデックスが取得されていることがわかります。

最後に、このチュートリアルで使用される GridView は、新しい製品を追加するために収集する必要があるフィールドの数が非常に大きいためです。 この幅のため、DetailsView の垂直レイアウトが推奨される場合があります。 GridView の全体的な幅は、収集する入力の数を減らすことで減らすことができます。 新しい製品を追加するときに、 UnitsOnOrderUnitsInStock、および ReorderLevel フィールドを収集する必要がない可能性があります。その場合、これらのフィールドは GridView から削除される可能性があります。

収集されたデータを調整するには、次の 2 つの方法のいずれかを使用します。

  • AddProductUnitsOnOrder、およびUnitsInStockフィールドの値を受け取るReorderLevelメソッドを引き続き使用します。 Inserting イベント ハンドラーで、挿入インターフェイスから削除されたこれらの入力に使用するハードコーディングされた既定値を指定します。
  • AddProductProductsBLL、およびUnitsOnOrderフィールドの入力を受け入れないUnitsInStock クラスに、ReorderLevel メソッドの新しいオーバーロードを作成します。 次に、ASP.NET ページで、この新しいオーバーロードを使用するように ObjectDataSource を構成します。

どちらのオプションも同様に機能します。 過去のチュートリアルでは、後者のオプションを使用して、 ProductsBLL クラスの UpdateProduct メソッドに対して複数のオーバーロードを作成しました。

概要

GridView には DetailsView と FormView に組み込みの挿入機能はありませんが、少し手間を省いて、挿入インターフェイスをフッター行に追加できます。 GridView でフッター行を表示するには、その ShowFooter プロパティを Trueに設定するだけです。 フッター行の内容は、フィールドを TemplateField に変換し、挿入インターフェイスを FooterTemplateに追加することで、フィールドごとにカスタマイズできます。 このチュートリアルで説明したように、 FooterTemplate には、Buttons、TextBoxes、DropDownLists、CheckBoxes、データ ドリブン Web コントロール (DropDownLists など) を設定するためのデータ ソース コントロール、および検証コントロールを含めることができます。 ユーザーの入力を収集するためのコントロールと共に、追加ボタン、LinkButton、または ImageButton が必要です。

[追加] ボタンをクリックすると、ObjectDataSource の Insert() メソッドが呼び出され、挿入ワークフローが開始されます。 その後、ObjectDataSource は、構成された insert メソッド (このチュートリアルでは、 ProductsBLL クラスの AddProduct メソッド) を呼び出します。 挿入メソッドを呼び出す前に、GridView の挿入インターフェイスから ObjectDataSource の InsertParameters コレクションに値をコピーする必要があります。 これを実現するには、ObjectDataSource の Inserting イベント ハンドラーに挿入インターフェイス Web コントロールをプログラムで参照します。

このチュートリアルでは、GridView の外観を向上させる手法について説明します。 次のチュートリアルセットでは、画像、PDF、Word 文書などのバイナリ データやデータ Web コントロールを操作する方法について説明します。

プログラミングに満足!

著者について

7 冊の ASP/ASP.NET 書籍の著者であり、4GuysFromRolla.com の創設者である Scott Mitchell は、1998 年から Microsoft Web テクノロジを使用しています。 Scott は、独立したコンサルタント、トレーナー、ライターとして働いています。 彼の最新の本は サムズ・ティーチ・セルフ ASP.NET 24時間で2.0です。 彼には mitchell@4GuysFromRolla.comで連絡できます。

特別な感謝

このチュートリアル シリーズは、多くの役に立つ校閲者によってレビューされました。 このチュートリアルのリード レビュー担当者はベルナデット リーでした。 今後の MSDN の記事を確認することに関心がありますか? その場合は、mitchell@4GuysFromRolla.comにメッセージを送ってください。