Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
Även om GridView-kontrollen inte ger inbyggt stöd för att infoga en ny datapost, visar den här självstudien hur du utökar GridView till att inkludera ett infogande gränssnitt.
Inledning
Som beskrivs i självstudien En översikt över infogning, uppdatering och borttagning av data , innehåller webbkontrollerna GridView, DetailsView och FormView inbyggda funktioner för datamodifiering. När de här tre webbkontrollerna används med deklarativa datakällkontroller kan de snabbt och enkelt konfigureras för att ändra data – och i scenarier utan att behöva skriva en enda kodrad. Tyvärr är det bara kontrollerna DetailsView och FormView som tillhandahåller inbyggda funktioner för infogning, redigering och borttagning. GridView erbjuder endast stöd för redigering och borttagning. Men med lite armbågsfett kan vi utöka GridView för att inkludera ett infogande gränssnitt.
När vi lägger till infogningsfunktioner i GridView ansvarar vi för att bestämma hur nya poster ska läggas till, skapa infogningsgränssnittet och skriva koden för att infoga den nya posten. I den här självstudien ska vi titta på hur du lägger till infogningsgränssnittet i GridViews sidfotsrad (se bild 1). Sidfotscellen för varje kolumn innehåller lämpligt användargränssnittselement för datainsamling (en textruta för produktens namn, en listruta för leverantören och så vidare). Vi behöver också en kolumn för knappen Lägg till, som vid klickning orsakar en postback och infogar en ny post i tabellen Products med hjälp av de värden som anges i sidfotens rad.
Bild 1: Sidfotsraden innehåller ett gränssnitt för att lägga till nya produkter (klicka om du vill visa en bild i full storlek)
Steg 1: Visa produktinformation i en GridView
Innan vi börjar med att skapa infogningsgränssnittet i GridView-sidfoten ska vi först fokusera på att lägga till en GridView på sidan som visar produkterna i databasen. Öppna sidan i InsertThroughFooter.aspx-mappen först och dra en GridView från verktygslådan till designern, och ställ in GridView’s EnhancedGridView-egenskap till ID. Använd sedan GridViews smarta tagg för att binda den till en ny ObjectDataSource med namnet ProductsDataSource.
              Bild 2: Skapa en ny ObjectDataSource med namnet ProductsDataSource (Klicka om du vill visa en bild i full storlek)
Konfigurera ObjectDataSource att använda ProductsBLL metoden class s GetProducts() för att hämta produktinformation. I den här självstudien ska vi fokusera strikt på att lägga till infogningsfunktioner och inte oroa dig för redigering och borttagning. Kontrollera därför att listrutan på fliken INSERT är inställd AddProduct() på och att listrutorna på flikarna UPPDATERA och TA BORT är inställda på (Ingen) .
              Bild 3: Mappa AddProduct metoden till ObjectDataSource-metoden Insert() (Klicka om du vill visa en bild i full storlek)
Bild 4: Ange flikarna UPPDATERA och TA BORT Drop-Down listor till (Ingen) (Klicka om du vill visa en bild i full storlek)
När du har slutfört guiden Konfigurera datakälla i ObjectDataSource lägger Visual Studio automatiskt till fält i GridView för vart och ett av motsvarande datafält. För tillfället lämnar du alla fält som lagts till av Visual Studio. Senare i den här handledningen kommer vi att ta bort några av de fält vars värden inte behöver anges när du lägger till en ny post.
Eftersom det finns nära 80 produkter i databasen måste en användare rulla hela vägen ned till slutet av webbsidan för att kunna lägga till en ny post. Låt oss därför aktivera sidindelning för att göra infogningsgränssnittet mer synligt och tillgängligt. Om du vill aktivera paging markerar du kryssrutan Aktivera paging från GridViews smarta tagg.
Nu bör GridView och ObjectDataSources deklarativa markering se ut ungefär så här:
<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>
Bild 5: Alla produktdatafält visas i en paginerad GridView (Klicka för att se bilden i full storlek)
Steg 2: Lägga till en sidfotsrad
Tillsammans med dess sidhuvud och datarader innehåller GridView en sidfotsrad. Sidhuvud- och sidfotsraderna visas beroende på värdena för GridView och ShowHeaderShowFooter egenskaperna. För att visa sidfotsraden ShowFooter ställ in inställningen till true. Som bild 6 visar, läggs en sidfotsrad till i rutnätet när egenskapen ShowFooter ställs in på true.
              Bild 6: Om du vill visa sidfotsraden anger du ShowFooter till True (Klicka om du vill visa en bild i full storlek)
Observera att sidfotsraden har en mörkröd bakgrundsfärg. Detta beror på DataWebControls-temat som vi skapade och tillämpade på alla sidor i handledningen Visa data med ObjectDataSource. 
              GridView.skin Mer specifikt konfigurerar FooterStyle filen egenskapen så att den FooterStyle använder CSS-klassen. Klassen FooterStyle definieras enligt Styles.css följande:
.FooterStyle
{
    background-color: #a33;
    color: White;
    text-align: right;
}
Anmärkning
Vi har utforskat användningen av en GridViews sidfotsrad i tidigare handledningar. Om det behövs kan du gå tillbaka till självstudiekursen om att visa sammanfattningsinformation i GridViewens sidfot för att fräscha upp minnet.
När du har angett ShowFooter-egenskapen till true, ta en stund för att titta på utdata i en webbläsare. För närvarande innehåller sidfotsraden inga text- eller webbkontroller. I steg 3 ändrar vi sidfoten för varje GridView-fält så att det innehåller lämpligt infogningsgränssnitt.
Bild 7: Den tomma sidfotsraden visas ovanför kontrollerna för växlingsgränssnittet (Klicka om du vill visa en bild i full storlek)
Steg 3: Anpassning av sidfotsraden
I självstudien Using TemplateFields i GridView Control såg vi hur vi kraftigt anpassade visningen av en viss GridView-kolumn med hjälp av TemplateFields (i motsats till BoundFields eller CheckBoxFields); i Anpassa datamodifieringsgränssnittet granskade vi hur man använde TemplateFields för att anpassa redigeringsgränssnittet i en GridView. Kom ihåg att ett TemplateField består av ett antal mallar som definierar blandningen av markering, webbkontroller och databindningssyntax som används för vissa typer av rader. , ItemTemplatetill exempel, anger mallen som används för skrivskyddade rader, medan EditItemTemplate definierar mallen för den redigerbara raden.
Tillsammans med ItemTemplate och EditItemTemplateinnehåller TemplateField även en FooterTemplate som anger innehållet för sidfotsraden. Därför kan vi lägga till de webbkontroller som behövs för varje fälts infogande gränssnitt i FooterTemplate. Börja genom att konvertera alla fält i GridView till TemplateFields. Detta kan göras genom att klicka på länken Redigera kolumner i GridViews smarta tagg, välja varje fält i det nedre vänstra hörnet och klicka på länken Konvertera det här fältet till en MallFält.
              
              
            
Bild 8: Konvertera varje fält till ett mallfält
När du klickar på fältet Konvertera det här fältet till ett TemplateField omvandlas den aktuella fälttypen till ett motsvarande TemplateField. Till exempel ersätts varje BoundField av ett TemplateField med en ItemTemplate som innehåller en etikett som visar motsvarande datafält och ett EditItemTemplate som visar datafältet i en textruta. 
              ProductName BoundField har konverterats till följande TemplateField-markering:
<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 På samma sätt har CheckBoxField konverterats till ett TemplateField vars ItemTemplate och EditItemTemplate innehåller en CheckBox-webbkontroll (med kryssrutan ItemTemplate inaktiverad). Det skrivskyddade ProductID BoundField har konverterats till ett TemplateField med en Label-kontroll i både ItemTemplate och EditItemTemplate. Kort och kort är konvertering av ett befintligt GridView-fält till ett TemplateField ett snabbt och enkelt sätt att växla till det mer anpassningsbara TemplateField utan att förlora någon av de befintliga fältfunktionerna.
Eftersom vi arbetar med en GridView som inte stöder redigering, kan du gärna ta bort EditItemTemplate från varje TemplateField och bara lämna ItemTemplate. När du har gjort detta bör gridview-deklarativa markering se ut så här:
<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>
Nu när varje GridView-fält har konverterats till ett TemplateField kan vi ange lämpligt infogningsgränssnitt i varje fält s FooterTemplate. Vissa av fälten har inget infogningsgränssnitt (ProductIDtill exempel), andra varierar i de webbkontroller som används för att samla in den nya produktens information.
Om du vill skapa redigeringsgränssnittet väljer du länken Redigera mallar från GridViews smarta tagg. I listrutan väljer du sedan lämpliga fält FooterTemplate och drar lämplig kontroll från verktygslådan till designern.
              Bild 9: Lägg till lämpligt infogningsgränssnitt FooterTemplate i varje fält (Klicka om du vill visa en bild i full storlek)
Följande punktlista räknar upp GridView-fälten och anger infogningsgränssnittet som ska läggas till:
- 
              
ProductIDingen. - 
              
ProductNamelägg till en textruta och ange dessIDtillNewProductName. Lägg även till en RequiredFieldValidator-kontroll för att säkerställa att användaren anger ett värde för den nya produktens namn. - 
              
SupplierIDingen. - 
              
CategoryIDingen. - 
              
QuantityPerUnitlägg till en textruta och ange dessIDtillNewQuantityPerUnit. - 
              
UnitPricelägg till en textruta med namnetNewUnitPriceoch en CompareValidator som säkerställer att det angivna värdet är ett valutavärde som är större än eller lika med noll. - 
              
UnitsInStockanvänd en textruta varsIDär inställd påNewUnitsInStock. Inkludera en CompareValidator som säkerställer att det angivna värdet är ett heltalsvärde som är större än eller lika med noll. - 
              
UnitsOnOrderanvänd en textruta varsIDär inställd påNewUnitsOnOrder. Inkludera en CompareValidator som säkerställer att det angivna värdet är ett heltalsvärde som är större än eller lika med noll. - 
              
ReorderLevelanvänd en textruta varsIDär inställd påNewReorderLevel. Inkludera en CompareValidator som säkerställer att det angivna värdet är ett heltalsvärde som är större än eller lika med noll. - 
              
Discontinuedlägg till en kryssruta och ange dessIDtillNewDiscontinued. - 
              
CategoryNamelägg till en dropdown-lista och ange dessIDtillNewCategoryID. Binda den till en ny ObjectDataSource med namnetCategoriesDataSourceoch konfigurera den så att denCategoriesBLLanvänder klassensGetCategories()-metod. Låt rullgardinslistanListItemvisaCategoryNamedatafältet och användaCategoryIDdatafältet som dess värden. - 
              
SupplierNamelägg till en dropdown-lista och ange dessIDtillNewSupplierID. Binda den till en ny ObjectDataSource med namnetSuppliersDataSourceoch konfigurera den så att denSuppliersBLLanvänder klassensGetSuppliers()-metod. Låt rullgardinslistanListItemvisaCompanyNamedatafältet och användaSupplierIDdatafältet som dess värden. 
För var och en av verifieringskontrollerna, rensa egenskapen ForeColor så att FooterStyle CSS-klassens vita förgrundsfärg används istället för den standardröda färgen. Använd även egenskapen ErrorMessage för en detaljerad beskrivning, men ange egenskapen Text till en asterisk. Om du vill förhindra att verifieringskontrollens text leder till att infogningsgränssnittet omsluts till två rader anger du FooterStyle egenskapen s Wrap till false för var och en av de FooterTemplate som använder en valideringskontroll. Lägg slutligen till en ValidationSummary-kontroll under GridView och ange dess ShowMessageBox egenskap till true och dess ShowSummary egenskap till false.
När du lägger till en ny produkt måste vi ange CategoryID och SupplierID. Den här informationen samlas in via listrutorna (DropDownLists) i sidfotscellerna för fälten CategoryName och SupplierName. Jag valde att använda dessa fält i motsats till mallfälten CategoryID och SupplierID eftersom användaren i rutnätets datarader sannolikt är mer intresserad av att se kategorin och leverantörsnamnen i stället för deras ID-värden. Eftersom värdena nu fångas i fälten i CategoryID och SupplierID för att infoga gränssnitt, kan vi ta bort mallfälten CategoryName och SupplierName från GridView.
På samma sätt används inte ProductID när du lägger till en ny produkt, så ProductID TemplateField kan också tas bort. Låt oss dock lämna fältet ProductID i rutnätet. Förutom kontrollerna TextBoxes, DropDownLists, CheckBoxes och validering som utgör infogningsgränssnittet behöver vi också en Lägg till-knapp som när du klickar på den utför logiken för att lägga till den nya produkten i databasen. I steg 4 ska vi inkludera knappen Lägg till i infogningsgränssnittet i ProductID TemplateFields FooterTemplate.
Du kan förbättra utseendet på de olika GridView-fälten. Du kanske till exempel vill formatera UnitPrice värdena som en valuta, högerjustera fälten UnitsInStock, UnitsOnOrderoch ReorderLevel och uppdatera HeaderText värdena för TemplateFields.
När du har skapat en mängd infogade gränssnitt i FooterTemplate s, tagit bort SupplierID, och CategoryID TemplateFields och förbättrat rutnätets estetik genom formatering och justering av TemplateFields bör rutnätets deklarativa markering se ut ungefär så här:
<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>
När den visas via en webbläsare innehåller GridViews sidfotsrad nu det slutförda infogningsgränssnittet (se bild 10). I det här läget innehåller inte infogningsgränssnittet något sätt för användaren att ange att hon har angett data för den nya produkten och vill infoga en ny post i databasen. Dessutom har vi ännu inte tagit upp hur de data som anges i sidfoten kommer att översättas till en ny post i Products databasen. I steg 4 ska vi titta på hur du inkluderar en lägg till-knapp i infogningsgränssnittet och hur du kör kod på postback när den klickas. Steg 5 visar hur du infogar en ny post med hjälp av data från sidfoten.
Bild 10: GridView-sidfoten tillhandahåller ett gränssnitt för att lägga till en ny post (Klicka om du vill visa en bild i full storlek)
Steg 4: Inkludera en lägg till knapp i infogningsgränssnittet
Vi måste inkludera knappen Lägg till någonstans i infogningsgränssnittet eftersom sidfotsradens infogningsgränssnitt för närvarande saknar möjlighet för användaren att ange att de har fyllt i den nya produktens information. Detta kan placeras i en av de befintliga FooterTemplate eller så kan vi lägga till en ny kolumn i rutnätet för detta ändamål. I den här handledningen placerar vi knappen Lägg till i ProductID TemplateField FooterTemplate.
Från designern klickar du på länken Redigera mallar i GridViews smarttagg och väljer sedan fältet ProductID i FooterTemplate listrutan. Lägg till en knappwebbkontroll (eller en LinkButton eller ImageButton, om du vill) till mallen och ange dess ID till AddProduct, dess CommandName till Infoga och dess Text egenskap till Lägg till enligt bild 11.
              Bild 11: Placera knappen Lägg till i mallfälten ProductIDFooterTemplate (Klicka om du vill visa en bild i full storlek)
När du har inkluderat knappen Lägg till testar du sidan i en webbläsare. Observera att när du klickar på knappen Lägg till med ogiltiga data i infogningsgränssnittet är postbacken kortsluten och kontrollen ValidationSummary anger ogiltiga data (se bild 12). Om du klickar på knappen Lägg till med lämpliga data returneras ett återanrop. Ingen post läggs dock till i databasen. Vi måste skriva lite kod för att faktiskt utföra infogningen.
Bild 12: Lägg till-knappens tillbakainskickning blir avbruten om det finns ogiltiga data i inmatningsgränssnittet (klicka för att visa bilden i full storlek)
Anmärkning
Verifieringskontrollerna i infogningsgränssnittet har inte tilldelats till en verifieringsgrupp. Detta fungerar bra så länge infogningsgränssnittet är den enda uppsättningen verifieringskontroller på sidan. Om det dock finns andra verifieringskontroller på sidan (till exempel verifieringskontroller i rutnätets redigeringsgränssnitt) bör verifieringskontrollerna i infogningsgränssnittet och Egenskaperna för Lägg till knapp tilldelas ValidationGroup samma värde för att associera dessa kontroller med en viss valideringsgrupp. Mer information om hur du partitionerar verifieringskontroller och knappar på en sida i valideringsgrupper finns i Dissekera valideringskontrollerna i ASP.NET 2.0 .
Steg 5: Infoga ett nytt rekord i tabellProducts
När du använder de inbyggda redigeringsfunktionerna i GridView hanterar GridView automatiskt allt arbete som krävs för att utföra uppdateringen. När du klickar på knappen Uppdatera kopieras de värden som anges från redigeringsgränssnittet till parametrarna i ObjectDataSource-samlingen UpdateParameters och startar uppdateringen genom att anropa metoden ObjectDataSource.Update() Eftersom GridView inte tillhandahåller sådana inbyggda funktioner för infogning måste vi implementera kod som anropar Metoden ObjectDataSource och Insert() kopierar värdena från infogningsgränssnittet till ObjectDataSource-samlingen InsertParameters .
Den här infogningslogik ska köras när knappen Lägg till har klickats på. Som diskuteras i självstudien "Lägga till och svara på knappar i en GridView", när en knapp, LinkButton eller ImageButton i ett GridView-objekt klickas på, utlöses GridView-händelsen RowCommand vid postback. Den här händelsen utlöses om knappen, LinkButton eller ImageButton uttryckligen lades till, till exempel knappen Lägg till i sidfotsraden eller om den lades till automatiskt av GridView (till exempel LinkButtons överst i varje kolumn när Aktivera sortering har valts, eller LinkButtons i växlingsgränssnittet när Aktivera växling har valts).
För att svara användaren som klickar på knappen Lägg till måste vi därför skapa en händelsehanterare för GridView-händelsen RowCommand . Eftersom den här händelsen utlöses när någon Knapp, LinkButton eller ImageButton i GridView klickas, är det viktigt att vi bara fortsätter med infogningslogik om CommandName egenskapen som skickas till händelsehanteraren mappar till CommandName värdet för knappen Lägg till ( Infoga ). Dessutom bör vi bara fortsätta om valideringskontrollerna rapporterar giltiga data. För att hantera detta skapar du en händelsehanterare för RowCommand händelsen med följande kod:
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...
    }
}
Anmärkning
Du kanske undrar varför händelsehanteraren bryr sig om att kontrollera Page.IsValid egenskapen. Blir inte postbacken undertryckt om ogiltiga data anges i insättningsgränssnittet? Det här antagandet är korrekt så länge användaren inte har inaktiverat JavaScript eller har vidtagit åtgärder för att kringgå valideringslogik på klientsidan. Kort och bra, man bör aldrig förlita sig strikt på validering på klientsidan. En kontroll på serversidan för giltighet bör alltid utföras innan du arbetar med data.
I steg 1 skapade ProductsDataSource vi ObjectDataSource så att dess Insert() metod mappas till ProductsBLL klassens AddProduct metod. För att infoga den nya posten i Products tabellen kan vi bara anropa metoden 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();
    }
}
Nu när Insert() metoden har anropats är allt som återstår att kopiera värdena från infogningsgränssnittet till de parametrar som skickas till ProductsBLL metoden class s AddProduct . Som vi såg i självstudiekursen Undersöka händelser som är associerade med infoga, uppdatera och ta bort kan detta utföras via ObjectDataSource-händelsen Inserting . Om Inserting vi behöver referera till kontrollerna programmatiskt från Products GridViews sidfotsrad och tilldela värdena till e.InputParameters samlingen. Om användaren utelämnar ett värde som att lämna ReorderLevel textrutan tom måste vi ange att värdet som infogas i databasen ska vara NULL. 
              AddProducts Eftersom metoden accepterar null-typer för de nullbara databasfälten använder du bara en nullbar typ och anger dess värde i null det fall då användarindata utelämnas.
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;
}
När händelsehanteraren Inserting har slutförts kan nya poster läggas till i databastabellen Products via GridViews sidfotsrad. Prova att lägga till flera nya produkter.
Förbättra och anpassa lägg till-åtgärden
När du klickar på knappen Lägg till läggs för närvarande en ny post till i databastabellen, men ingen visuell feedback om att posten har lagts till. Helst skulle en etikettwebbkontroll eller aviseringsruta på klientsidan informera användaren om att deras infogning har slutförts. Jag lämnar detta som en övning för läsaren.
GridView som används i den här självstudien tillämpar inte någon sorteringsordning på de listade produkterna och tillåter inte heller slutanvändaren att sortera data. Därför sorteras posterna som de är i databasen efter deras primära nyckelfält. Eftersom varje ny post har ett ProductID värde som är större än det föregående, läggs varje ny produkt till slutet av rutnätet. Därför kanske du vill skicka användaren automatiskt till den sista sidan i GridView när du har lagt till en ny post. Detta kan åstadkommas genom att lägga till följande kodrad efter anropet till ProductsDataSource.Insert() i RowCommand händelsehanteraren för att indikera att användaren måste skickas till den sista sidan efter att data har bindts till GridView:
// Indicate that the user needs to be sent to the last page
SendUserToLastPage = true;
              SendUserToLastPage är en boolesk variabel på sidnivå som ursprungligen tilldelas värdet false. I GridView-händelsehanteraren DataBound, om SendUserToLastPage är falskt, uppdateras egenskapen PageIndex för att skicka användaren till den sista sidan.
protected void Products_DataBound(object sender, EventArgs e)
{
    // Send user to last page of data, if needed
    if (SendUserToLastPage)
        Products.PageIndex = Products.PageCount - 1;
}
Anledningen till att PageIndex-egenskapen anges i DataBound-händelsehanteraren (till skillnad från RowCommand-händelsehanteraren) beror på att när RowCommand-händelsehanteraren utlöses har vi ännu inte lagt till den nya posten i Products-databastabellen. 
              RowCommand I händelsehanteraren representerar därför det sista sidindexet (PageCount - 1) det sista sidindexet innan den nya produkten har lagts till. För de flesta produkter som läggs till är indexet för sista sidan detsamma när du har lagt till den nya produkten. Men när den tillagda produkten resulterar i ett nytt index för sista sidan, om vi felaktigt uppdaterar PageIndex i RowCommand händelsehanteraren, kommer vi att tas till den näst sista sidan (det sista sidindexet innan vi lägger till den nya produkten) i motsats till det nya indexet för sista sidan. Eftersom DataBound händelsehanteraren utlöses efter att den nya produkten har lagts till och data återbinds till rutnätet, vet vi genom att ange PageIndex egenskapen där att vi får rätt index för sista sidan.
Slutligen är den GridView som används i denna handledning ganska bred på grund av antalet fält som måste anges för att lägga till en ny produkt. På grund av den här bredden kan en Lodrät Layout för DetailsView föredras. GridViews totala bredd kan minskas genom att samla in färre indata. Vi kanske inte behöver samla in fälten UnitsOnOrder, UnitsInStockoch ReorderLevel när du lägger till en ny produkt, i vilket fall dessa fält kan tas bort från GridView.
För att justera de data som samlas in kan vi använda någon av två metoder:
- Fortsätt att använda den 
AddProductmetod som förväntar sig värden för fältenUnitsOnOrder,UnitsInStockochReorderLevel.InsertingI händelsehanteraren anger du hårdkodade standardvärden som ska användas för de indata som har tagits bort från infogningsgränssnittet. - Skapa en ny överlagring av 
AddProductmetoden iProductsBLLklassen som inte accepterar indata för fältenUnitsOnOrder,UnitsInStockochReorderLevel. På sidan ASP.NET konfigurerar du sedan ObjectDataSource för att använda den här nya överlagringen. 
Båda alternativen fungerar lika bra. I tidigare självstudier använde vi det senare alternativet och skapade flera överbelastningar för ProductsBLL-klassens UpdateProduct-metod.
Sammanfattning
GridView saknar de inbyggda infogningsfunktionerna som finns i DetailsView och FormView, men med lite ansträngning kan ett infogande gränssnitt läggas till i sidfotsraden. Om du vill visa sidfotsraden i en GridView anger du helt enkelt dess ShowFooter egenskap till true. Sidfotsradens innehåll kan anpassas för varje fält genom att konvertera fältet till ett TemplateField och lägga till infogningsgränssnittet i FooterTemplate. Som vi såg i den här självstudien kan den FooterTemplate innehålla knappar, textrutor, listrutor, kryssrutor, datakällkontroller för att fylla i datadrivna webbkontroller (till exempel listrutor) och verifieringskontroller. Tillsammans med kontroller för att samla in användarens indata behövs en Lägg till knapp, LinkButton eller ImageButton.
När knappen Lägg till klickas anropas metoden ObjectDataSources Insert() för att starta arbetsflödet för infogning. ObjectDataSource anropar sedan den angivna insert-metoden ( ProductsBLL klassens AddProduct metod i den här handledningen). Vi måste kopiera värdena från GridView-infogningsgränssnittet till ObjectDataSource-samlingen InsertParameters innan infogningsmetoden anropas. Detta kan åstadkommas genom att programmatiskt referera till webbkontrollerna för infogningsgränssnittet i ObjectDataSources Inserting händelsehanterare.
Den här handledningen avslutar vår genomgång av tekniker för att förbättra utseendet på GridView. Nästa uppsättning självstudier kommer att undersöka hur du arbetar med binära data, till exempel bilder, PDF-filer, Word-dokument och så vidare och datawebbkontrollerna.
Lycka till med programmerandet!
Om författaren
Scott Mitchell, författare till sju ASP/ASP.NET-böcker och grundare av 4GuysFromRolla.com, har arbetat med Microsofts webbtekniker sedan 1998. Scott arbetar som oberoende konsult, tränare och författare. Hans senaste bok är Sams Teach Yourself ASP.NET 2.0 på 24 timmar. Han kan nås på mitchell@4GuysFromRolla.com.
Särskilt tack till
Den här självstudieserien granskades av många användbara granskare. Ansvarig granskare för den här självstudien var Bernadette Leigh. Vill du granska mina kommande MSDN-artiklar? Om så är fallet, hör av dig på mitchell@4GuysFromRolla.com.