從 GridView 的頁尾插入新記錄 (C#)
雖然 GridView 控件不提供插入新數據記錄的內建支援,但本教學課程會示範如何增強 GridView 以包含插入介面。
簡介
如 插入、更新和刪除數據 的概觀中所述,GridView、DetailsView 和 FormView Web 控制件都包含內建的數據修改功能。 搭配宣告式數據源控件使用時,這三個 Web 控件可以快速且輕鬆地設定為修改數據,而且在案例中不需要撰寫單行程式代碼。 可惜的是,只有 DetailsView 和 FormView 控件提供內建的插入、編輯和刪除功能。 GridView 僅提供編輯和刪除支援。 不過,有了一點橢圓形,我們可以增強 GridView 以包含插入介面。
在將插入功能新增至 GridView 中,我們會負責決定新記錄的新增方式、建立插入介面,以及撰寫程式代碼以插入新記錄。 在本教學課程中,我們將探討如何將插入介面新增至 GridView 的頁尾數據列, (請參閱圖 1) 。 每個數據行的頁尾單元格包含適當的數據收集使用者介面元素 (產品名稱的 TextBox、供應商的 DropDownList 等等) 。 我們也需要 [新增] 按鈕的數據行,當按兩下時,將會導致回傳,並使用頁尾數據列中提供的值,將 Products
新記錄插入數據表中。
圖 1:頁尾數據列提供新增產品的介面, (按兩下即可檢視完整大小的影像)
步驟 1:在 GridView 中顯示產品資訊
在我們擔心在 GridView 頁尾中建立插入介面之前,讓我們先專注於將 GridView 新增至列出資料庫中產品的頁面。 首先,InsertThroughFooter.aspx
開啟資料夾中的頁面EnhancedGridView
,並將 GridView 從 [工具箱] 拖曳至 Designer,然後將 GridView s ID
屬性設定為 Products
。 接下來,使用 GridView 的智慧標記將它系結至名為 ProductsDataSource
的新 ObjectDataSource。
圖 2:建立名為 ProductsDataSource
的新 ObjectDataSource (按兩下即可檢視大小完整的映射)
設定 ObjectDataSource 以使用 ProductsBLL
類別 s GetProducts()
方法來擷取產品資訊。 在本教學課程中,讓我們嚴格專注於新增插入功能,而不擔心編輯和刪除。 因此,請確定 INSERT 索引標籤中的下拉式清單已設定 AddProduct()
為 ,且 UPDATE 和 DELETE 索引標籤標的下拉式清單已設定為 ([無]) 。
圖 3:將 AddProduct
方法對應至 ObjectDataSource s Insert()
方法 (按兩下即可檢視大小完整的影像)
圖 4:將 UPDATE 和 DELETE 索引標籤 Drop-Down 清單 (設定為 [無]) (按兩下即可檢視大小完整的映像)
完成 ObjectDataSource 的 [設定數據源精靈] 之後,Visual Studio 會自動為每個對應的數據字段新增至 GridView。 目前,請保留 Visual Studio 新增的所有欄位。 稍後在本教學課程中,我們將返回並移除新增記錄時不需要指定其值的一些欄位。
由於資料庫中有接近 80 個產品,因此用戶必須向下卷動到網頁底部,才能新增記錄。 因此,讓我們啟用分頁,讓插入介面更可見且更容易存取。 若要開啟分頁,只要從 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
設定 屬性,以便使用 FooterStyle
CSS 類別。 類別 FooterStyle
的定義 Styles.css
如下:
.FooterStyle
{
background-color: #a33;
color: White;
text-align: right;
}
注意
我們已在先前的教學課程中使用 GridView 的頁尾數據列進行探索。 如有需要,請參閱 GridView 的頁尾教學課程中顯示摘要資訊 ,以取得重新整理。
將 屬性設定 ShowFooter
為 true
之後,請花點時間在瀏覽器中檢視輸出。 目前頁尾數據列不包含任何文字或 Web 控制件。 在步驟 3 中,我們將修改每個 GridView 欄位的頁尾,使其包含適當的插入介面。
圖 7:空白頁尾列會顯示在分頁介面控件上方, (按兩下即可檢視大小完整的影像)
步驟 3:自定義頁尾數據列
回到 使用 GridView 控件中的 TemplateFields 教學課程,我們瞭解如何使用 TemplateFields (來大幅自定義特定 GridView 數據行的顯示,而不是 BoundFields 或 CheckBoxFields) ;在 自定義數據修改介面 中,我們查看了如何使用TemplateFields自定義 GridView 中的編輯介面。 回想一下,TemplateField 是由一些範本所組成,可定義用於特定數據列類型的標記、Web 控件和數據系結語法的混合。 例如,會 ItemTemplate
指定用於唯讀數據列的範本,而 EditItemTemplate
會定義可編輯數據列的範本。
ItemTemplate
除了和 EditItemTemplate
之外,TemplateField 也包含 ,FooterTemplate
指定頁尾數據列的內容。 因此,我們可以將每個欄位插入介面所需的 Web 控制項新增至 FooterTemplate
。 若要開始,請將 GridView 中的所有字段轉換為 TemplateFields。 您可以按下 GridView 智慧標記中的 [編輯資料行] 連結、選取左下角中的每個字段,然後按兩下 [將此字位轉換成 TemplateField] 連結來完成。
圖 8:將每個字段轉換成 TemplateField
按兩下 [將此欄位轉換成 TemplateField] 會將目前的欄位類型轉換成對等的 TemplateField。 例如,每個 BoundField 都會由 TemplateField ItemTemplate
取代為 ,其中包含顯示對應數據欄位的 Label,以及在 EditItemTemplate
TextBox 中顯示資料欄位的 。 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 已轉換成 TemplateField,其中同時具有 和 EditItemTemplate
中的 ItemTemplate
Label 控件。 簡單來說,將現有的 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
然後將適當的控件從 [工具箱] 拖曳至 Designer。
圖 9:將適當的插入介面新增至每個欄位 (FooterTemplate
按兩下即可檢視大小完整的影像)
下列點符清單會列舉 GridView 欄位,並指定要新增的插入介面:
ProductID
沒有。ProductName
新增 TextBox 並將設定ID
為NewProductName
。 同時新增 RequiredFieldValidator 控件,以確保使用者輸入新產品名稱的值。SupplierID
沒有。CategoryID
沒有。QuantityPerUnit
新增 TextBox,將其ID
設定為NewQuantityPerUnit
。UnitPrice
新增名為NewUnitPrice
的 TextBox 和 CompareValidator,以確保輸入的值是大於或等於零的貨幣值。UnitsInStock
使用設定NewUnitsInStock
為的ID
TextBox。 包含 CompareValidator,以確保輸入的值是大於或等於零的整數值。UnitsOnOrder
使用設定NewUnitsOnOrder
為的ID
TextBox。 包含 CompareValidator,以確保輸入的值是大於或等於零的整數值。ReorderLevel
使用設定NewReorderLevel
為的ID
TextBox。 包含 CompareValidator,以確保輸入的值是大於或等於零的整數值。Discontinued
新增 CheckBox,並將其ID
設定為NewDiscontinued
。CategoryName
新增 DropDownList 並將設定ID
為NewCategoryID
。 將它系結至名為CategoriesDataSource
的新 ObjectDataSource,並將其設定為使用CategoriesBLL
類別 sGetCategories()
方法。 讓DropDownListListItem
顯示CategoryName
資料欄位,並使用CategoryID
資料欄位作為其值。SupplierName
新增 DropDownList 並將設定ID
為NewSupplierID
。 將它系結至名為SuppliersDataSource
的新 ObjectDataSource,並將其設定為使用SuppliersBLL
類別 sGetSuppliers()
方法。 讓DropDownListListItem
顯示CompanyName
資料欄位,並使用SupplierID
資料欄位作為其值。
針對每個驗證控件,清除 ForeColor
屬性, FooterStyle
以便使用 CSS 類別的白色前景色彩來取代預設紅色。 也請使用 ErrorMessage
屬性作為詳細描述,但將 Text
屬性設定為星號。 若要防止驗證控件的文字造成插入介面換行到兩行,請將每個FooterTemplate
使用驗證控件的 屬性Wrap
設定FooterStyle
為 false。 最後,在 GridView 下方新增 ValidationSummary 控件,並將其 屬性設定為 true
ShowSummary
,並將其 ShowMessageBox
屬性設定為 false
。
新增產品時,我們需要提供 CategoryID
和 SupplierID
。 此資訊會透過和 SupplierName
欄位的頁尾單元格CategoryName
中的DropDownLists擷取。 我選擇使用這些欄位,而不是 CategoryID
和 SupplierID
TemplateFields,因為在方格的數據列中,使用者可能更有興趣查看類別和供應商名稱,而不是其標識碼值。 CategoryID
由於 和 值現在會擷取在 和 SupplierID
SupplierName
欄位的插入介面中CategoryName
,因此我們可以從 GridView 移除 CategoryID
和 SupplierID
TemplateFields。
同樣地, ProductID
新增產品時不會使用 ,因此 ProductID
也可以移除 TemplateField。 不過,讓我們將 ProductID
欄位保留在方格中。 除了組成插入介面的 TextBoxes、DropDownLists、CheckBoxes 和驗證控件之外,我們也需要 [新增] 按鈕,按兩下時,執行邏輯以將新產品新增至資料庫。 在步驟 4 中,我們會在 TemplateField s FooterTemplate
的插入介面ProductID
中包含 [新增] 按鈕。
您可以隨意改善各種 GridView 字段的外觀。 例如,您可能想要將值格式化 UnitPrice
為貨幣、靠右對齊 UnitsInStock
、 UnitsOnOrder
和 ReorderLevel
字段,以及更新 HeaderText
TemplateFields 的值。
在 s 中 FooterTemplate
建立插入介面的斜流、移除 SupplierID
、 和 CategoryID
TemplateFields,以及透過格式化和對齊 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 s FooterTemplate
中。
從 Designer 中,按兩下 GridView 智慧標記中的 [編輯範本] 連結,然後ProductID
從下拉式清單中選擇字段FooterTemplate
。 如果您想要) 範本,將按鈕 Web 控件 (或 LinkButton 或 ImageButton,將其標識元設定為 、CommandName
將其設定為 AddProduct
[插入],並將其Text
屬性新增至 [新增],如圖 11 所示。
圖 11:將 [新增按鈕] 放在 ProductID
TemplateField s FooterTemplate
(Click 以檢視完整大小的影像)
加入 [新增] 按鈕之後,請在瀏覽器中測試頁面。 請注意,按下插入介面中具有無效數據的 [新增] 按鈕時,回傳會縮短,而 ValidationSummary 控件表示無效的數據 (請參閱圖 12) 。 輸入適當的數據后,按兩下 [新增] 按鈕會導致回傳。 不過,不會將任何記錄新增至資料庫。 我們需要撰寫一些程序代碼,才能實際執行插入。
圖 12:如果插入介面中有無效數據,則 [新增按鈕回傳] 會縮短 (按兩下即可檢視大小完整的影像)
注意
插入介面中的驗證控制件未指派給驗證群組。 只要插入介面是頁面上唯一的一組驗證控件,這即可正常運作。 不過,如果頁面上有其他驗證控件 (例如方格編輯介面中的驗證控件) ,則插入介面和 [新增] 按鈕 s ValidationGroup
屬性中的驗證控件應該指派相同的值,以便將這些控件與特定驗證群組產生關聯。 如需將頁面上的驗證控件和按鈕分割成驗證群組的詳細資訊,請參閱 剖析 ASP.NET 2.0 中的驗證控件 。
步驟 5:將新記錄插入Products
數據表
使用 GridView 的內建編輯功能時,GridView 會自動處理執行更新所需的所有工作。 特別是單擊 [更新] 按鈕時,它會將從編輯介面輸入的值複製到 ObjectDataSource 集合 UpdateParameters
中的參數,並叫用 ObjectDataSource s Update()
方法啟動更新。 由於 GridView 不提供這類內建功能來插入,因此我們必須實作程式代碼來呼叫 ObjectDataSource s Insert()
方法,並將值從插入介面複製到 ObjectDataSource s InsertParameters
集合。
按兩下 [新增] 按鈕之後,應該執行此插入邏輯。 如同 在 GridView 教學課程中新增和響應按鈕 中所討論,每當按兩下 GridView 中的 Button、LinkButton 或 ImageButton 時,GridView 事件 RowCommand
就會在回傳時引發。 此事件會引發此事件,不論已明確新增 Button、LinkButton 或 ImageButton,例如頁尾列中的 [新增] 按鈕,或是當選取 [啟用分頁] 時,GridView 會自動新增它 (例如選取 [啟用排序] 時,每個數據行頂端的 LinkButtons,或選取 [啟用分頁] 時,在分頁介面中的 LinkButtons) 。
因此,若要回應使用者按兩下 [新增] 按鈕,我們需要建立 GridView 事件的 RowCommand
事件處理程式。 由於每當按兩下 GridView 中的任何 Button、LinkButton 或 ImageButton 時,就會引發此事件,因此只有在傳遞至事件處理程式的屬性會對應至 CommandName
[新增] 按鈕的值 ( Insert ) 時,才繼續執行插入邏輯CommandName
。 此外,只有在驗證控件報告有效數據時,我們也應該繼續進行。 若要容納這種情況,請使用下列程式代碼建立 RowCommand
事件的事件處理程式:
protected void Products_RowCommand(object sender, GridViewCommandEventArgs e)
{
// Insert data if the CommandName == "Insert"
// and the validation controls indicate valid data...
if (e.CommandName == "Insert" && Page.IsValid)
{
// TODO: Insert new record...
}
}
注意
您可能想知道事件處理程式檢查 Page.IsValid
屬性的原因。 之後,如果插入介面中提供無效的數據,將不會隱藏回傳? 只要使用者尚未停用 JavaScript 或已採取步驟來規避客戶端驗證邏輯,此假設是正確的。 簡言之,絕對不應該依賴客戶端驗證;使用數據之前,應該一律執行伺服器端檢查是否有效。
在步驟 1 中,我們建立了 ProductsDataSource
ObjectDataSource, Insert()
使其方法對應至 ProductsBLL
類別 s AddProduct
方法。 若要將新記錄 Products
插入數據表中,我們只要叫用 ObjectDataSource s Insert()
方法即可:
protected void Products_RowCommand(object sender, GridViewCommandEventArgs e)
{
// Insert data if the CommandName == "Insert"
// and the validation controls indicate valid data...
if (e.CommandName == "Insert" && Page.IsValid)
{
// Insert new record
ProductsDataSource.Insert();
}
}
Insert()
現在已叫用 方法,剩下的就是將插入介面中的值複製到傳遞至ProductsBLL
類別 s AddProduct
方法的參數。 如我們在 檢查與插入、更新和刪除相關的事件 教學課程中所見,這可以透過 ObjectDataSource s Inserting
事件來完成。 Inserting
在此情況下,我們需要以程序設計方式參考 GridView 頁尾數據列中的控件Products
,並將其值指派給e.InputParameters
集合。 如果使用者省略一個值, ReorderLevel
例如將 TextBox 保留空白,我們需要指定插入資料庫的值應該是 NULL
。 AddProducts
由於方法會接受可為 Null 之資料庫欄位的可為 Null 型別,因此只要使用可為 Null 的類型,並在省略使用者輸入的情況下將其值設定為 null
。
protected void ProductsDataSource_Inserting
(object sender, ObjectDataSourceMethodEventArgs e)
{
// Programmatically reference Web controls in the inserting interface...
TextBox NewProductName =
(TextBox)Products.FooterRow.FindControl("NewProductName");
DropDownList NewCategoryID =
(DropDownList)Products.FooterRow.FindControl("NewCategoryID");
DropDownList NewSupplierID =
(DropDownList)Products.FooterRow.FindControl("NewSupplierID");
TextBox NewQuantityPerUnit =
(TextBox)Products.FooterRow.FindControl("NewQuantityPerUnit");
TextBox NewUnitPrice =
(TextBox)Products.FooterRow.FindControl("NewUnitPrice");
TextBox NewUnitsInStock =
(TextBox)Products.FooterRow.FindControl("NewUnitsInStock");
TextBox NewUnitsOnOrder =
(TextBox)Products.FooterRow.FindControl("NewUnitsOnOrder");
TextBox NewReorderLevel =
(TextBox)Products.FooterRow.FindControl("NewReorderLevel");
CheckBox NewDiscontinued =
(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);
string quantityPerUnit = null;
if (!string.IsNullOrEmpty(NewQuantityPerUnit.Text))
quantityPerUnit = NewQuantityPerUnit.Text;
e.InputParameters["quantityPerUnit"] = quantityPerUnit;
decimal? unitPrice = null;
if (!string.IsNullOrEmpty(NewUnitPrice.Text))
unitPrice = Convert.ToDecimal(NewUnitPrice.Text);
e.InputParameters["unitPrice"] = unitPrice;
short? unitsInStock = null;
if (!string.IsNullOrEmpty(NewUnitsInStock.Text))
unitsInStock = Convert.ToInt16(NewUnitsInStock.Text);
e.InputParameters["unitsInStock"] = unitsInStock;
short? unitsOnOrder = null;
if (!string.IsNullOrEmpty(NewUnitsOnOrder.Text))
unitsOnOrder = Convert.ToInt16(NewUnitsOnOrder.Text);
e.InputParameters["unitsOnOrder"] = unitsOnOrder;
short? reorderLevel = null;
if (!string.IsNullOrEmpty(NewReorderLevel.Text))
reorderLevel = Convert.ToInt16(NewReorderLevel.Text);
e.InputParameters["reorderLevel"] = reorderLevel;
e.InputParameters["discontinued"] = NewDiscontinued.Checked;
}
完成事件處理程序之後 Inserting
,即可透過 GridView 的頁尾數據列,將新的記錄新增至 Products
資料庫數據表。 繼續並嘗試新增數個新產品。
增強和自定義新增作業
目前,按兩下 [新增] 按鈕會將新記錄新增至資料庫數據表,但不提供任何一種已成功新增記錄的視覺回饋。 在理想情況下,標籤 Web 控制項或用戶端警示方塊會通知使用者其插入已順利完成。 我將此專案保留為讀者的練習。
本教學課程中使用的 GridView 不會將任何排序順序套用至列出的產品,也不會允許使用者排序數據。 因此,記錄會依主鍵欄位在資料庫中排序。 由於每個新記錄的值都大於最後一筆 ProductID
,因此每次將新產品新增至網格線結尾時。 因此,您可能想要在新增記錄之後,自動將用戶傳送至 GridView 的最後一頁。 這可以藉由在事件處理程式中RowCommand
呼叫 ProductsDataSource.Insert()
之後新增下列程式代碼行來完成,以指出在將數據系結至 GridView 之後,用戶必須傳送至最後一頁:
// Indicate that the user needs to be sent to the last page
SendUserToLastPage = true;
SendUserToLastPage
是一開始指派 值 false
的頁面層級布爾值變數。 在 GridView 的 DataBound
事件處理程式中,如果 SendUserToLastPage
為 false,則會 PageIndex
更新 屬性,以將使用者傳送至最後一頁。
protected void Products_DataBound(object sender, EventArgs e)
{
// Send user to last page of data, if needed
if (SendUserToLastPage)
Products.PageIndex = Products.PageCount - 1;
}
屬性在事件處理程式中設定的原因 PageIndex
(,而不是RowCommand
事件處理程式) 是因為當事件處理程序引發時RowCommand
,我們尚未將新記錄新增至Products
資料庫DataBound
數據表。 因此,在事件處理程式中 RowCommand
,最後一頁索引 (PageCount - 1
) 代表新增新產品 之前 的最後一頁索引。 對於大部分要新增的產品,在新增新產品之後,最後一頁索引會相同。 但是,當新增的產品產生新的最後一頁索引時,如果我們在事件處理程式中RowCommand
不正確地更新 PageIndex
,則會在新增新產品之前,先將第二頁到最後一頁 (最後一頁索引,再新增新產品) ,而不是新的最後一頁索引。 DataBound
由於事件處理程式會在新增產品且數據重新系結至方格之後引發,因此我們會在該處設定PageIndex
屬性,我們知道我們取得正確的最後一頁索引。
最後,本教學課程中使用的 GridView 相當廣泛,因為必須收集才能新增產品的欄位數目。 由於此寬度,可能會偏好使用DetailsView的垂直版面配置。 GridView 的整體寬度可以藉由收集較少的輸入來減少。 或許我們不需要在新增產品時收集 UnitsOnOrder
、 UnitsInStock
和 ReorderLevel
字段,在此情況下,這些欄位可以從 GridView 中移除。
若要調整收集的數據,我們可以使用下列兩種方法之一:
- 繼續使用
AddProduct
預期、UnitsInStock
和ReorderLevel
欄位值UnitsOnOrder
的方法。 在事件處理程式中Inserting
,提供硬式編碼的預設值,以用於已從插入介面中移除的這些輸入。 - 在類別中
ProductsBLL
建立方法的新多載,這個多載AddProduct
不接受 、UnitsInStock
和ReorderLevel
欄位的UnitsOnOrder
輸入。 然後,在 [ASP.NET] 頁面中,將 ObjectDataSource 設定為使用此新的多載。
任一選項也一樣運作。 在過去教學課程中,我們使用後者選項,為 ProductsBLL
類別 s UpdateProduct
方法建立多個多載。
摘要
GridView 缺少 DetailsView 和 FormView 中找到的內建插入功能,但插入介面可以新增至頁尾數據列。 若要在 GridView 中顯示頁尾資料列,只要將其 ShowFooter
屬性設定為 true
。 您可以將欄位轉換成 TemplateField,並將插入介面新增至 ,來自定義每個欄位的 FooterTemplate
頁尾數據列內容。 如本教學課程中所見, FooterTemplate
可以包含 Buttons、TextBoxes、DropDownLists、CheckBoxes、用於填入數據驅動 Web 控件的數據源控件 (,例如 DropDownLists) 和驗證控件。 除了收集使用者輸入的控件之外,還需要 [新增按鈕]、[LinkButton] 或 [ImageButton]。
按兩下 [新增] 按鈕時,會叫用 ObjectDataSource s Insert()
方法來啟動插入工作流程。 然後,ObjectDataSource 會在本教學課程) (ProductsBLL
類別方法呼叫已設定的 AddProduct
insert 方法。 我們必須在叫用 insert 方法之前,先將 GridView 的插入介面中的值複製到 ObjectDataSource s InsertParameters
集合。 這可以透過程式設計方式參考 ObjectDataSource 事件處理程式 Inserting
中的插入介面 Web 控件來完成。
本教學課程會完成增強 GridView 外觀的技術。 下一組教學課程將檢查如何使用二進位數據,例如影像、PDF、Word 檔等等,以及數據 Web 控制項。
快樂的程序設計!
關於作者
Scott Mitchell 是七份 ASP/ASP.NET 書籍的作者,以及 自 1998 年以來與 Microsoft Web 技術合作的 4GuysFromRolla.com 作者。 Scott 是獨立顧問、訓練員和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格來連線到 ,您可以在 找到http://ScottOnWriting.NET。
特別感謝
本教學課程系列是由許多實用的檢閱者檢閱。 本教學課程的首席檢閱者是 Bernadette 一文。 有興趣檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行 mitchell@4GuysFromRolla.com放在 。