從 GridView 的頁尾插入新記錄 (VB)

作者 :Scott Mitchell

下載 PDF

雖然 GridView 控件不提供插入新記錄的內建支援,但本教學課程會示範如何增強 GridView 以包含插入介面。

簡介

插入、更新和刪除數據 的概觀教學課程所述,GridView、DetailsView 和 FormView Web 控件都包含內建的數據修改功能。 搭配宣告式數據源控件使用時,這三個 Web 控件可以快速且輕鬆地設定為修改數據,而且在案例中不需要撰寫單行程式代碼。 可惜的是,只有 DetailsView 和 FormView 控件提供內建插入、編輯和刪除功能。 GridView 僅提供編輯和刪除支援。 不過,有了一點橢圓形,我們可以增強 GridView 以包含插入介面。

在將插入功能新增至 GridView 中,我們負責決定新記錄的新增方式、建立插入介面,以及撰寫程式代碼以插入新記錄。 在本教學課程中,我們將探討如何將插入介面新增至 GridView 的頁尾數據列, (請參閱圖 1) 。 每個數據行的頁尾單元格包含適當的數據收集使用者介面元素, (產品名稱的 TextBox、供應商的 DropDownList 等) 。 我們也需要 [新增] 按鈕的數據行,當按兩下時,會導致回傳,並使用頁尾數據列中提供的值,將新記錄 Products 插入數據表中。

頁尾數據列提供新增產品的介面

圖 1:頁尾數據列提供新增產品的介面, (按兩下即可檢視完整大小的影像)

步驟 1:在 GridView 中顯示產品資訊

在我們擔心在 GridView 頁尾中建立插入介面之前,讓我們先專注於將 GridView 新增至列出資料庫中產品的頁面。 從開啟資料夾中的頁面開始,InsertThroughFooter.aspx並將 GridView 從 [工具箱] 拖曳至 Designer,將 GridView 的 ID 屬性設定為 ProductsEnhancedGridView 接下來,使用 GridView 的智慧標記將它系結至名為 ProductsDataSource的新 ObjectDataSource。

建立名為 ProductsDataSource 的新 ObjectDataSource

圖 2:建立名為 ProductsDataSource 的新 ObjectDataSource (按兩下即可檢視完整大小的影像)

設定 ObjectDataSource 以使用 ProductsBLL 類別 s GetProducts() 方法來擷取產品資訊。 在本教學課程中,讓我們嚴格專注於新增插入功能,而不必擔心編輯和刪除。 因此,請確定 INSERT 索引標籤中的下拉式清單設定為 AddProduct() ,且 UPDATE 和 DELETE 索引標籤標的下拉式清單設定為 [無]) (。

將 AddProduct 方法對應至 ObjectDataSource s Insert () 方法

圖 3:將 AddProduct 方法對應至 ObjectDataSource s Insert() 方法, (按兩下即可檢視完整大小的影像)

將 UPDATE 和 DELETE 索引標籤 Drop-Down 清單 設定為 ([無)

圖 4:將 [更新] 和 [刪除] 索引標籤 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>

所有產品數據欄位都會顯示在Paged GridView 中

圖 5:所有產品數據欄位都會顯示在 Paged GridView 中, (按兩下即可檢視完整大小的影像)

GridView 及其頁首和數據列也包含頁尾數據列。 頁首和頁尾數據列會根據 GridView 的值 ShowHeaderShowFooter 屬性來顯示。 若要顯示頁尾資料列,只要將 ShowFooter 屬性設定為 True。 如圖 6 所示,將 屬性設定 ShowFooterTrue 將頁尾數據列新增至方格。

若要顯示頁尾數據列,請將 ShowFooter 設定為 True

圖 6:若要顯示頁尾數據列,請設定 ShowFooterTrue (按兩下即可檢視完整大小的影像)

請注意,頁尾數據列具有深紅色的背景色彩。 這是因為我們在使用 ObjectDataSource 顯示數據 教學課程中建立並套用至所有頁面的 DataWebControls 主題。 具體而言,檔案會GridView.skinFooterStyle設定 屬性,以使用 FooterStyle CSS 類別。 類別 FooterStyle 定義於 中 Styles.css ,如下所示:

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

注意

我們已在先前的教學課程中使用 GridView 的頁尾數據列進行探索。 如有需要,請參閱 GridView 頁尾教學課程中的顯示摘要資訊 以取得重新整理。

ShowFooter 屬性設定為 True之後,請花一點時間在瀏覽器中檢視輸出。 頁尾列目前不包含任何文字或 Web 控制件。 在步驟 3 中,我們將修改每個 GridView 欄位的頁尾,使其包含適當的插入介面。

空白頁尾列會顯示在分頁介面控件上方

圖 7:空白頁尾數據列會顯示在分頁介面控件上方, (按兩下即可檢視完整大小的影像)

回到 使用 GridView 控件中的 TemplateFields 教學課程中,我們已瞭解如何使用 TemplateFields (來大幅自定義特定 GridView 數據行的顯示,而不是 BoundFields 或 CheckBoxFields) ;在 自定義數據修改介面 中,我們探討如何使用TemplateFields自定義 GridView 中的編輯介面。 回想一下,TemplateField 是由許多範本所組成,可定義用於特定數據列類型的標記、Web 控件和數據系結語法混合。 ItemTemplate例如,會指定用於唯讀數據列的範本,而 EditItemTemplate 會定義可編輯數據列的範本。

除了 ItemTemplateEditItemTemplate之外,TemplateField 也包含 , FooterTemplate 指定頁尾數據列的內容。 因此,我們可以將每個欄位插入介面所需的 Web 控制項新增至 FooterTemplate。 若要開始,請將 GridView 中的所有字段轉換成 TemplateFields。 您可以按下 GridView 智慧標記中的 [編輯資料行] 連結、選取左下角的每個字段,然後按兩下 [將此字位轉換成 TemplateField] 連結來完成。

將每個欄位轉換成 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,其中包含 ItemTemplateEditItemTemplate 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。

將適當的插入介面新增至每個欄位的 FooterTemplate

圖 9:將適當的插入介面新增至每個欄位 FooterTemplate (按兩下即可檢視完整大小的影像)

下列點符清單會列舉 GridView 欄位,並指定要加入的插入介面:

  • ProductID 沒有。
  • ProductName 新增 TextBox,並將設定 IDNewProductName。 新增 RequiredFieldValidator 控件,以確保使用者輸入新產品名稱的值。
  • SupplierID 沒有。
  • CategoryID 沒有。
  • QuantityPerUnit 新增 TextBox,並將設定 IDNewQuantityPerUnit
  • UnitPrice 新增名為 NewUnitPrice 的 TextBox 和 CompareValidator,以確保輸入的值是大於或等於零的貨幣值。
  • UnitsInStock使用設定為NewUnitsInStockID TextBox。 包含 CompareValidator,以確保輸入的值是大於或等於零的整數值。
  • UnitsOnOrder使用設定為NewUnitsOnOrderID TextBox。 包含 CompareValidator,以確保輸入的值是大於或等於零的整數值。
  • ReorderLevel使用設定為NewReorderLevelID TextBox。 包含 CompareValidator,以確保輸入的值是大於或等於零的整數值。
  • Discontinued 新增 CheckBox,並將設定 IDNewDiscontinued
  • CategoryName 新增 DropDownList 並將設定 IDNewCategoryID。 將它系結至名為 CategoriesDataSource 的新 ObjectDataSource,並將其設定為使用 CategoriesBLL 類別 s GetCategories() 方法。 讓DropDownList顯示ListItemCategoryName資料欄位,並使用CategoryID資料欄位作為其值。
  • SupplierName 新增 DropDownList 並將設定 IDNewSupplierID。 將它系結至名為 SuppliersDataSource 的新 ObjectDataSource,並將其設定為使用 SuppliersBLL 類別 s GetSuppliers() 方法。 讓DropDownList顯示ListItemCompanyName資料欄位,並使用SupplierID資料欄位作為其值。

針對每個驗證控件,清除 ForeColor 屬性, FooterStyle 讓 CSS 類別的白色前景色彩會用來取代預設紅色。 另請使用 ErrorMessage 屬性進行詳細描述,但將 Text 屬性設定為星號。 若要防止驗證控件的文字造成插入介面換行成兩行,請將FooterStyle每個FooterTemplate使用驗證控件的 屬性Wrap設定為 false。 最後,在 GridView 底下新增 ValidationSummary 控件,並將其 屬性設定為 True ,並將其 ShowSummary 屬性設定ShowMessageBoxFalse

新增產品時,我們需要提供 CategoryIDSupplierID。 此資訊是透過和 SupplierName 欄位頁尾單元格CategoryName中的DropDownLists擷取。 我選擇使用這些欄位,而不是 CategoryIDSupplierID TemplateFields,因為在方格的數據列中,使用者可能更有興趣查看類別和供應商名稱,而不是其標識碼值。 CategoryID由於 和 SupplierID 值現在正在 和 SupplierName 欄位插入介面中CategoryName擷取,我們可以從 GridView 移除 CategoryIDSupplierID TemplateFields。

同樣地, ProductID 新增產品時不會使用 ,因此 ProductID 也可以移除 TemplateField。 不過,讓我們將欄位保留在 ProductID 方格中。 除了組成插入介面的 TextBoxes、DropDownLists、CheckBox 和驗證控件之外,我們也需要 [新增] 按鈕,當按兩下時,執行邏輯以將新產品新增至資料庫。 在步驟 4 中,我們會在 TemplateField s FooterTemplate的插入介面ProductID中包含 [新增] 按鈕。

您可以隨意改善各種 GridView 字段的外觀。 例如,您可能想要將值格式化 UnitPrice 為貨幣、靠右對齊 UnitsInStockUnitsOnOrderReorderLevel 字段,並更新 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 示範如何使用頁尾的數據來插入新記錄。

GridView 頁尾提供用來新增記錄的介面

圖 10:GridView 頁尾提供用來新增記錄的介面, (按兩下即可檢視大小完整的影像)

步驟 4:在插入介面中包含 [新增] 按鈕

我們需要在插入介面中包含 [新增] 按鈕,因為頁尾數據列的插入介面目前缺少表示使用者已完成輸入新產品資訊的方法。 這可以放在其中一個現有的 FooterTemplate ,或者我們可以為此目的將新的數據行新增至方格。 在本教學課程中,讓我們將 [新增] 按鈕放在 ProductID TemplateField s FooterTemplate中。

從 Designer,按兩下 GridView 智慧標記中的 [編輯範本] 連結,然後從下拉式清單中選擇ProductID字段FooterTemplate。 如果您想要將按鈕 Web 控件) (或 LinkButton 或 ImageButton,請將它識別元設定為 、將其標識元 AddProduct設定為 、將其 CommandName 屬性設定為 [插入],以及將屬性 Text 設定為 [新增],如圖 11 所示。

將 [新增] 按鈕放在 ProductID TemplateField s FooterTemplate

圖 11:將 [新增按鈕] ProductID 放在 TemplateField s FooterTemplate (按兩下以檢視大小完整的影像)

一旦您包含 [新增] 按鈕,請在瀏覽器中測試頁面。 請注意,按下插入介面中具有無效數據的 [新增] 按鈕時,回傳會縮短,而 ValidationSummary 控件表示無效的數據 (請參閱圖 12) 。 輸入適當的數據后,按兩下 [新增] 按鈕會導致回傳。 不過,不會將任何記錄新增至資料庫。 我們需要撰寫一些程序代碼,才能實際執行插入。

如果插入介面中有無效的數據,[新增按鈕回傳] 會縮短

圖 12:如果插入介面中的數據無效,[新增按鈕回傳] 會縮短 (按兩下即可檢視大小完整的影像)

注意

插入介面中的驗證控制件未指派給驗證群組。 只要插入介面是頁面上唯一的一組驗證控件,這才能正常運作。 不過,如果頁面上有其他驗證控件 (例如網格線編輯介面中的驗證控件) ,則插入介面和 [新增] 按鈕屬性 ValidationGroup 中的驗證控件應該指派相同的值,以便將這些控件與特定的驗證群組產生關聯。 如需將頁面上的驗證控件和按鈕分割成驗證群組的詳細資訊,請參閱 剖析 ASP.NET 2.0 中的 驗證控件。

步驟 5:將新記錄Products插入數據表

使用 GridView 的內建編輯功能時,GridView 會自動處理執行更新所需的所有工作。 特別是,按兩下 [更新] 按鈕時,它會將從編輯介面輸入的值複製到 ObjectDataSource s 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 s RowCommand 事件的事件處理程式。 由於每當按兩下 GridView 中的任何 Button、LinkButton 或 ImageButton 時,就會引發此事件,因此只有在傳遞至事件處理程式的 屬性對應至 CommandName [新增] 按鈕的值 ( Insert ) 時,我們才必須繼續進行插入邏輯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 我們建立了 ObjectDataSource, Insert() 使其方法對應至 ProductsBLL 類別 s AddProduct 方法。 若要將新記錄 Products 插入數據表中,我們可以直接叫用 ObjectDataSource s 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類別 s AddProduct 方法的參數。 如我們在 檢查與插入、更新和刪除相關的事件 教學課程中所見,這可以透過 ObjectDataSource s Inserting 事件來完成。 在此情況下, Inserting 我們需要以程序設計方式參考 GridView 頁尾數據列中的控件 Products ,並將其值指派給 e.InputParameters 集合。 如果使用者省略值,例如將 TextBox 保留空白, ReorderLevel 我們需要指定插入資料庫的值應該是 NULLAddProducts由於 方法接受可為 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 的最後一頁。 這可以藉由在事件處理程式中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 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) 代表新產品 新增前 的最後一頁索引。 針對正在新增的大部分產品,在新增新產品之後,最後一頁索引會相同。 但是,當新增的產品產生新的最後一頁索引時,如果我們在事件處理程式中RowCommand不正確地更新 PageIndex ,則會將我們帶至第二頁到最後一頁 (最後一頁索引,再新增新產品) ,而不是新的最後一頁索引。 由於事件處理程式會在 DataBound 新增產品之後引發,而且數據會重新系結至方格,方法是 PageIndex 設定該處的 屬性,我們知道我們會取得正確的最後一頁索引。

最後,本教學課程中使用的 GridView 相當廣泛,因為必須收集的欄位數目才能新增新產品。 由於此寬度,建議使用DetailsView的垂直版面配置。 GridView 的整體寬度可以藉由收集較少的輸入來減少。 或許在新增產品時,我們不需要收集 UnitsOnOrderUnitsInStockReorderLevel 欄位,在此情況下,這些欄位可以從 GridView 中移除。

若要調整收集的數據,我們可以使用下列兩種方法之一:

  • 繼續使用AddProduct預期、 UnitsInStockReorderLevel 欄位值UnitsOnOrder的方法。 在事件處理程式中 Inserting ,提供硬式編碼的預設值,以用於已從插入介面中移除的這些輸入。
  • 在類別中ProductsBLL建立方法的新多載AddProduct,這個類別不接受 、 UnitsInStockReorderLevel 欄位的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 會呼叫已設定的 insert 方法, (ProductsBLL 類別 s AddProduct 方法,在本教學課程中) 。 在叫用 insert 方法之前,我們必須將 GridView 插入介面中的值複製到 ObjectDataSource s InsertParameters 集合。 這可以透過以程式設計方式參考 ObjectDataSource 事件處理程式 Inserting 中的插入介面 Web 控件來完成。

本教學課程會完成增強 GridView 外觀的技術。 下一組教學課程將探討如何使用二進位數據,例如影像、PDF、Word 檔等等,以及數據 Web 控制項。

快樂的程序設計!

關於作者

Scott Mitchell 是 1998 年以來,1998 年與 Microsoft Web 技術合作的 篇 ASP/ASP.NET 書籍和 4GuysFromRolla.com 作者。 Scott 是獨立的顧問、訓練者和作者。 他的最新書籍是 Sams 在 24 小時內自行 ASP.NET 2.0。 您可以透過mitchell@4GuysFromRolla.com部落格連到,也可以透過其部落格來存取,網址為 http://ScottOnWriting.NET

特別感謝

本教學課程系列是由許多實用的檢閱者所檢閱。 本教學課程的首席檢閱者是 Bernadette 一文。 想要檢閱即將推出的 MSDN 文章嗎? 如果是,請將一行放在 mitchell@4GuysFromRolla.com。