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 にバインドします。
図 2: 名前付きの新しい ObjectDataSource ProductsDataSource
を作成する (フルサイズの画像を表示する をクリックします)
ProductsBLL
クラスの GetProducts()
メソッドを使用して製品情報を取得するように ObjectDataSource を構成します。 このチュートリアルでは、挿入機能の追加に重点を置き、編集や削除について心配しないようにしましょう。 そのため、[INSERT] タブのドロップダウン リストが AddProduct()
に設定されていること、および [UPDATE] タブと [DELETE] タブのドロップダウン リストが [なし] に設定されていることを確認します。
図 3: AddProduct
メソッドを ObjectDataSource の Insert()
メソッドにマップします (フルサイズの画像を表示する をクリックします)。
図 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>
図 5: すべての製品データ フィールドが Paged GridView に表示されます (フルサイズの画像を表示する をクリックします)。
手順 2: フッター行を追加する
GridView には、ヘッダー行とデータ行に加えて、フッター行が含まれます。 ヘッダーとフッターの行は、GridView の ShowHeader
プロパティと ShowFooter
プロパティの値に応じて表示されます。 フッター行を表示するには、 ShowFooter
プロパティを True
に設定するだけです。 図 6 に示すように、 ShowFooter
プロパティを True
に設定すると、フッター行がグリッドに追加されます。
図 6: フッター行を表示するには、 ShowFooter
を True
に設定します (フルサイズの画像を表示する をクリックします)。
フッター行の背景色は濃い赤色であることに注意してください。 これは、 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: 空のフッター行がページング インターフェイス コントロールの上に表示されます (フルサイズの画像を表示する をクリックします)。
手順 3: フッター行をカスタマイズする
GridView コントロールのチュートリアルの TemplateFields の使用に戻り、(BoundFields や CheckBoxFields ではなく) TemplateFields を使用して特定の GridView 列の表示を大幅にカスタマイズする方法について説明しました。「データ変更インターフェイスのカスタマイズ」で、TemplateFields を使用して GridView の編集インターフェイスをカスタマイズする方法について説明しました。 TemplateField は、特定の種類の行に使用されるマークアップ、Web コントロール、およびデータ バインド構文の組み合わせを定義する多数のテンプレートで構成されていることを思い出してください。 たとえば、 ItemTemplate
は読み取り専用行に使用されるテンプレートを指定しますが、 EditItemTemplate
では編集可能な行のテンプレートが定義されます。
ItemTemplate
とEditItemTemplate
に加えて、TemplateField にはフッター行の内容を指定するFooterTemplate
も含まれています。 そのため、インターフェイスを挿入する各フィールドに必要な Web コントロールを FooterTemplate
に追加できます。 開始するには、GridView 内のすべてのフィールドを TemplateFields に変換します。 これを行うには、GridView のスマート タグの [列の編集] リンクをクリックし、左下隅の各フィールドを選択し、[このフィールドを 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 に変換され、その ItemTemplate
と EditItemTemplate
には CheckBox Web コントロールが含まれています ( ItemTemplate
の CheckBox が無効になっています)。 読み取り専用 ProductID
BoundField は、 ItemTemplate
と EditItemTemplate
の両方で 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
を選択し、ツールボックスからデザイナーに適切なコントロールをドラッグします。
図 9: 各フィールドの FooterTemplate
に適切な挿入インターフェイスを追加します (フルサイズの画像を表示する をクリックします)。
次の箇条書きでは、追加する挿入インターフェイスを指定して、GridView フィールドを列挙します。
-
ProductID
なし。 -
ProductName
テキスト ボックスを追加し、そのID
をNewProductName
に設定します。 RequiredFieldValidator コントロールを追加して、ユーザーが新しい製品名の値を入力するようにします。 -
SupplierID
なし。 -
CategoryID
なし。 -
QuantityPerUnit
テキスト ボックスを追加し、そのID
をNewQuantityPerUnit
に設定します。 -
UnitPrice
NewUnitPrice
という名前の TextBox と、入力した値が 0 以上の通貨値であることを確認する CompareValidator を追加します。 -
UnitsInStock
ID
がNewUnitsInStock
に設定されている TextBox を使用します。 入力した値が 0 以上の整数値であることを保証する CompareValidator を含めます。 -
UnitsOnOrder
ID
がNewUnitsOnOrder
に設定されている TextBox を使用します。 入力した値が 0 以上の整数値であることを保証する CompareValidator を含めます。 -
ReorderLevel
ID
がNewReorderLevel
に設定されている TextBox を使用します。 入力した値が 0 以上の整数値であることを保証する CompareValidator を含めます。 -
Discontinued
CheckBox を追加し、そのID
をNewDiscontinued
に設定します。 -
CategoryName
DropDownList を追加し、そのID
をNewCategoryID
に設定します。CategoriesDataSource
という名前の新しい ObjectDataSource にバインドし、CategoriesBLL
クラスのGetCategories()
メソッドを使用するように構成します。 DropDownListListItem
にCategoryName
データ フィールドを表示し、CategoryID
データ フィールドを値として使用します。 -
SupplierName
DropDownList を追加し、そのID
をNewSupplierID
に設定します。SuppliersDataSource
という名前の新しい ObjectDataSource にバインドし、SuppliersBLL
クラスのGetSuppliers()
メソッドを使用するように構成します。 DropDownListListItem
にCompanyName
データ フィールドを表示し、SupplierID
データ フィールドを値として使用します。
検証コントロールごとに、 ForeColor
プロパティをクリアして、 FooterStyle
CSS クラスの白い前景色が既定の赤の代わりに使用されるようにします。 また、詳細な説明には ErrorMessage
プロパティを使用しますが、 Text
プロパティをアスタリスクに設定します。 検証コントロールのテキストによって挿入インターフェイスが 2 行に折り返されないようにするには、検証コントロールを使用する各FooterStyle
に対して、Wrap
の FooterTemplate
プロパティを false に設定します。 最後に、GridView の下に ValidationSummary コントロールを追加し、その ShowMessageBox
プロパティを True
に設定し、その ShowSummary
プロパティを False
に設定します。
新しい製品を追加するときは、 CategoryID
と SupplierID
を提供する必要があります。 この情報は、 CategoryName
フィールドと SupplierName
フィールドのフッター セルの DropDownLists を介してキャプチャされます。 グリッドのデータ行では、ユーザーが ID 値ではなくカテゴリ名とサプライヤー名を表示することに関心がある可能性が高いため、 CategoryID
と SupplierID
TemplateFields ではなく、これらのフィールドを使用することを選択しました。
CategoryID
とSupplierID
の値は、CategoryName
およびSupplierName
フィールドの挿入インターフェイスにキャプチャされるため、GridView から CategoryID
および SupplierID
TemplateFields を削除できます。
同様に、 ProductID
は新しい製品を追加するときに使用されないため、 ProductID
TemplateField も削除できます。 ただし、グリッドの [ ProductID
] フィールドはそのままにしておきます。 挿入インターフェイスを構成する TextBoxes、DropDownLists、CheckBoxes、検証コントロールに加えて、[追加] ボタンも必要です。このボタンをクリックすると、新しい製品をデータベースに追加するロジックが実行されます。 手順 4 では、 ProductID
TemplateField の FooterTemplate
の挿入インターフェイスに [追加] ボタンを含めます。
さまざまな GridView フィールドの外観を自由に改善してください。 たとえば、 UnitPrice
値を通貨として書式設定し、 UnitsInStock
、 UnitsOnOrder
、および 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 では、フッターのデータを使用して新しいレコードを挿入する方法を示します。
図 10: GridView フッターは、新しいレコードを追加するためのインターフェイスを提供します (フルサイズの画像を表示する をクリックします)。
手順 4: 挿入インターフェイスに追加ボタンを含める
フッター行の挿入インターフェイスには現在、ユーザーが新製品の情報の入力を完了したことを示す手段がないため、挿入インターフェイスのどこかに [追加] ボタンを含める必要があります。 これは、既存の FooterTemplate
のいずれかに配置することも、この目的のためにグリッドに新しい列を追加することもできます。 このチュートリアルでは、 ProductID
TemplateField の FooterTemplate
に [追加] ボタンを配置します。
デザイナーで、GridView のスマート タグの [テンプレートの編集] リンクをクリックし、ドロップダウン リストからProductID
FooterTemplate
フィールドを選択します。 図 11 に示すように、テンプレートに Button Web コントロール (または必要に応じて LinkButton または ImageButton) を追加し、その ID を AddProduct
に設定し、その CommandName
を Insert に、 Text
プロパティを Add に設定します。
図 11: ProductID
TemplateField の FooterTemplate
に [追加] ボタンを配置する (フルサイズの画像を表示する をクリックします)
[追加] ボタンを含めたら、ブラウザーでページをテストします。 挿入インターフェイスで無効なデータを含む [追加] ボタンをクリックすると、ポストバックがショートし、ValidationSummary コントロールが無効なデータを示します (図 12 を参照)。 適切なデータを入力すると、[追加] ボタンをクリックするとポストバックが発生します。 ただし、データベースにはレコードは追加されません。 実際に挿入を実行するには、少しコードを記述する必要があります。
図 12: 挿入インターフェイスに無効なデータがある場合、[追加ボタン] のポストバックはショートサーキットされます (フルサイズの画像を表示するにはクリックします)
注
挿入インターフェイスの検証コントロールが検証グループに割り当てされませんでした。 これは、挿入インターフェイスがページ上の検証コントロールの唯一のセットである限り、正常に動作します。 ただし、ページに他の検証コントロール (グリッドの編集インターフェイスの検証コントロールなど) がある場合は、挿入インターフェイスの検証コントロールと [追加] ボタンの ValidationGroup
プロパティに、これらのコントロールを特定の検証グループに関連付けるために同じ値を割り当てる必要があります。 ページ上 の検証コントロールとボタンを検証グループに分割する 方法の詳細については、ASP.NET 2.0 の検証コントロールの分割に関するページを参照してください。
手順 5: Products
Table に新しいレコードを挿入する
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 の全体的な幅は、収集する入力の数を減らすことで減らすことができます。 新しい製品を追加するときに、 UnitsOnOrder
、 UnitsInStock
、および ReorderLevel
フィールドを収集する必要がない可能性があります。その場合、これらのフィールドは GridView から削除される可能性があります。
収集されたデータを調整するには、次の 2 つの方法のいずれかを使用します。
-
AddProduct
、UnitsOnOrder
、およびUnitsInStock
フィールドの値を受け取るReorderLevel
メソッドを引き続き使用します。Inserting
イベント ハンドラーで、挿入インターフェイスから削除されたこれらの入力に使用するハードコーディングされた既定値を指定します。 -
AddProduct
、ProductsBLL
、および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にメッセージを送ってください。