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

作者: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開啟資料夾中的頁面EnhancedGridView,並將 GridView 從 [工具箱] 拖曳至 Designer,然後將 GridView s ID 屬性設定為 Products。 接下來,使用 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:將 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 中, (按兩下即可檢視完整大小的影像)

除了其標頭和數據列之外,GridView 也包含頁尾數據列。 根據 GridView 和 ShowHeader 屬性的值,會顯示頁首和 ShowFooter 頁尾數據列。 若要顯示頁尾資料列,只需將 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 的頁尾教學課程中顯示摘要資訊 ,以取得重新整理。

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

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

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

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

ItemTemplate除了和 EditItemTemplate之外,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,將其 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 並將設定 IDNewCategoryID。 將它系結至名為 CategoriesDataSource 的新 ObjectDataSource,並將其設定為使用 CategoriesBLL 類別 s GetCategories() 方法。 讓DropDownList ListItem 顯示 CategoryName 資料欄位,並使用 CategoryID 資料欄位作為其值。
  • SupplierName 新增 DropDownList 並將設定 IDNewSupplierID。 將它系結至名為 SuppliersDataSource 的新 ObjectDataSource,並將其設定為使用 SuppliersBLL 類別 s GetSuppliers() 方法。 讓DropDownList ListItem 顯示 CompanyName 資料欄位,並使用 SupplierID 資料欄位作為其值。

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

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

同樣地, ProductID 新增產品時不會使用 ,因此 ProductID 也可以移除 TemplateField。 不過,讓我們將 ProductID 欄位保留在方格中。 除了組成插入介面的 TextBoxes、DropDownLists、CheckBoxes 和驗證控件之外,我們也需要 [新增] 按鈕,按兩下時,執行邏輯以將新產品新增至資料庫。 在步驟 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,將其標識元設定為 、CommandName將其設定為 AddProduct[插入],並將其Text屬性新增至 [新增],如圖 11 所示。

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

圖 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 保留空白,我們需要指定插入資料庫的值應該是 NULLAddProducts由於方法會接受可為 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 的整體寬度可以藉由收集較少的輸入來減少。 或許我們不需要在新增產品時收集 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 會在本教學課程) (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放在 。