Share via


Inserir um novo registro do rodapé do GridView (C#)

por Scott Mitchell

Baixar PDF

Embora o controle GridView não forneça suporte interno para inserir um novo registro de dados, este tutorial mostra como aumentar o GridView para incluir uma interface de inserção.

Introdução

Conforme discutido no tutorial Uma visão geral de inserção, atualização e exclusão de dados , os controles Web GridView, DetailsView e FormView incluem recursos internos de modificação de dados. Quando usados com controles declarativos de fonte de dados, esses três controles da Web podem ser configurados de forma rápida e fácil para modificar dados – e em cenários sem a necessidade de escrever uma única linha de código. Infelizmente, somente os controles DetailsView e FormView fornecem recursos internos de inserção, edição e exclusão. O GridView oferece apenas suporte para edição e exclusão. No entanto, com um pouco de graxa de cotovelo, podemos aumentar o GridView para incluir uma interface de inserção.

Ao adicionar recursos de inserção ao GridView, somos responsáveis por decidir como novos registros serão adicionados, criar a interface de inserção e escrever o código para inserir o novo registro. Neste tutorial, veremos como adicionar a interface de inserção à linha de rodapé do GridView (consulte a Figura 1). A célula de rodapé de cada coluna inclui o elemento de interface do usuário de coleta de dados apropriado (um TextBox para o nome do produto, um DropDownList para o fornecedor e assim por diante). Também precisamos de uma coluna para um botão Adicionar que, quando clicado, causará um postback e inserirá um novo registro na Products tabela usando os valores fornecidos na linha de rodapé.

A linha footer fornece uma interface para adicionar novos produtos

Figura 1: a linha rodapé fornece uma interface para adicionar novos produtos (clique para exibir a imagem em tamanho real)

Etapa 1: Exibindo informações do produto em um GridView

Antes de nos preocuparmos com a criação da interface de inserção no rodapé do GridView, primeiro vamos nos concentrar em adicionar um GridView à página que lista os produtos no banco de dados. Comece abrindo a InsertThroughFooter.aspx página na EnhancedGridView pasta e arraste um GridView da Caixa de Ferramentas para o Designer, definindo a propriedade ProductsGridView como ID . Em seguida, use a marca inteligente GridView para associá-la a um novo ObjectDataSource chamado ProductsDataSource.

Criar um novo objectDataSource chamado ProductsDataSource

Figura 2: Criar um novo objectDataSource chamado ProductsDataSource (clique para exibir a imagem em tamanho real)

Configure o ObjectDataSource para usar o ProductsBLL método da classe s GetProducts() para recuperar informações do produto. Para este tutorial, vamos nos concentrar estritamente em adicionar recursos de inserção e não se preocupar em editar e excluir. Portanto, verifique se a lista suspensa na guia INSERT está definida AddProduct() como e se as listas suspensas nas guias UPDATE e DELETE estão definidas como (Nenhum).

Mapear o método AddProduct para o método Insert() objectDataSource

Figura 3: Mapear o AddProduct método para o método ObjectDataSource (Insert()clique para exibir a imagem em tamanho real)

Defina as guias UPDATE e DELETE Drop-Down Listas como (Nenhum)

Figura 4: Definir as guias UPDATE e DELETE Drop-Down Listas como (Nenhum) (Clique para exibir a imagem em tamanho real)

Depois de concluir o assistente Configurar Fonte de Dados do ObjectDataSource, o Visual Studio adicionará automaticamente campos ao GridView para cada um dos campos de dados correspondentes. Por enquanto, deixe todos os campos adicionados pelo Visual Studio. Posteriormente neste tutorial, voltaremos e removeremos alguns dos campos cujos valores não precisam ser especificados ao adicionar um novo registro.

Como há cerca de 80 produtos no banco de dados, um usuário terá que rolar todo o caminho até a parte inferior da página da Web para adicionar um novo registro. Portanto, vamos habilitar a paginação para tornar a interface de inserção mais visível e acessível. Para ativar a paginação, basta marcar a caixa de seleção Habilitar Paginação da marca inteligente GridView.

Neste ponto, a marcação declarativa de GridView e ObjectDataSource deve ser semelhante à seguinte:

<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>

Todos os campos de dados do produto são exibidos em um Paged GridView

Figura 5: Todos os campos de dados do produto são exibidos em um Paged GridView (clique para exibir a imagem em tamanho real)

Juntamente com seu cabeçalho e linhas de dados, o GridView inclui uma linha de rodapé. As linhas de cabeçalho e rodapé são exibidas dependendo dos valores das propriedades e ShowFooter gridViewShowHeader. Para mostrar a linha de rodapé, basta definir a ShowFooter propriedade como true. Como ilustra a Figura 6, definir a ShowFooter propriedade para true adicionar uma linha de rodapé à grade.

Para exibir a linha do rodapé, defina ShowFooter como True

Figura 6: Para exibir a linha do rodapé, defina ShowFooter como True (clique para exibir a imagem em tamanho real)

Observe que a linha do rodapé tem uma cor da tela de fundo vermelha escura. Isso ocorre devido ao Tema DataWebControls que criamos e aplicamos a todas as páginas no tutorial Exibindo dados com o ObjectDataSource . Especificamente, o GridView.skin arquivo configura a FooterStyle propriedade de modo que é usa a FooterStyle classe CSS. A FooterStyle classe é definida em Styles.css da seguinte maneira:

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

Observação

Exploramos o uso da linha de rodapé do GridView em tutoriais anteriores. Se necessário, consulte o tutorial Exibindo informações de resumo no Rodapé do GridView para obter um atualizador.

Depois de definir a ShowFooter propriedade truecomo , reserve um momento para exibir a saída em um navegador. Atualmente, a linha do rodapé não contém nenhum texto ou controles da Web. Na Etapa 3, modificaremos o rodapé de cada campo GridView para que ele inclua a interface de inserção apropriada.

A linha de rodapé vazia é exibida acima dos controles da interface de paginação

Figura 7: a linha de rodapé vazia é exibida acima dos controles da interface de paginação (clique para exibir a imagem em tamanho real)

De volta ao tutorial Usando TemplateFields no Controle GridView , vimos como personalizar muito a exibição de uma determinada coluna GridView usando TemplateFields (em vez de BoundFields ou CheckBoxFields); em Personalizando a interface de modificação de dados que examinamos usando TemplateFields para personalizar a interface de edição em um GridView. Lembre-se de que um TemplateField é composto por vários modelos que definem a combinação de marcação, controles Da Web e sintaxe de vinculação de dados usada para determinados tipos de linhas. O ItemTemplate, por exemplo, especifica o modelo usado para linhas somente leitura, enquanto o EditItemTemplate define o modelo para a linha editável.

Junto com o ItemTemplate e EditItemTemplateo , o TemplateField também inclui um FooterTemplate que especifica o conteúdo da linha de rodapé. Portanto, podemos adicionar os controles da Web necessários para cada interface de inserção de campo no FooterTemplate. Para iniciar, converta todos os campos no GridView em TemplateFields. Isso pode ser feito clicando no link Editar Colunas na marca inteligente GridView, selecionando cada campo no canto inferior esquerdo e clicando no link Converter este campo em um TemplateField.

Converter cada campo em um TemplateField

Figura 8: Converter cada campo em um TemplateField

Clicar no campo Converter este campo em um TemplateField transforma o tipo de campo atual em um TemplateField equivalente. Por exemplo, cada BoundField é substituído por um TemplateField por um ItemTemplate que contém um Label que exibe o campo de dados correspondente e um EditItemTemplate que exibe o campo de dados em um TextBox. O ProductName BoundField foi convertido na seguinte marcação 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>

Da mesma forma, o Discontinued CheckBoxField foi convertido em um TemplateField cujo ItemTemplate e EditItemTemplate contêm um controle Web CheckBox (com o ItemTemplate s CheckBox desabilitado). O BoundField somente ProductID leitura foi convertido em um TemplateField com um controle Label no e EditItemTemplateno ItemTemplate . Em suma, converter um campo GridView existente em um TemplateField é uma maneira rápida e fácil de alternar para o TemplateField mais personalizável sem perder nenhuma das funcionalidades existentes do campo.

Como o GridView com o qual estamos trabalhando não dá suporte à edição, fique à vontade para remover o EditItemTemplate de cada TemplateField, deixando apenas o ItemTemplate. Depois de fazer isso, a marcação declarativa do GridView deve ser semelhante à seguinte:

<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>

Agora que cada campo GridView foi convertido em um TemplateField, podemos inserir a interface de inserção apropriada em cada campo s FooterTemplate. Alguns dos campos não terão uma interface de inserção (ProductIDpor exemplo); outros variam nos controles da Web usados para coletar as informações do novo produto.

Para criar a interface de edição, escolha o link Editar Modelos na marca inteligente GridView. Em seguida, na lista suspensa, selecione os campos apropriados FooterTemplate e arraste o controle apropriado da Caixa de Ferramentas para o Designer.

Adicionar a interface de inserção apropriada a cada footerTemplate de campo

Figura 9: Adicionar a interface de inserção apropriada a cada campo s FooterTemplate (clique para exibir a imagem em tamanho real)

A seguinte lista com marcadores enumera os campos GridView, especificando a interface de inserção a ser adicionada:

  • ProductID Nenhum.
  • ProductName adicione uma TextBox e defina como IDNewProductName. Adicione um controle RequiredFieldValidator também para garantir que o usuário insira um valor para o nome do novo produto.
  • SupplierID Nenhum.
  • CategoryID Nenhum.
  • QuantityPerUnit adicione uma TextBox, definindo-a IDNewQuantityPerUnitcomo .
  • UnitPrice adicione um TextBox chamado NewUnitPrice e um CompareValidator que garante que o valor inserido seja um valor de moeda maior ou igual a zero.
  • UnitsInStock use uma TextBox cujo ID está definido como NewUnitsInStock. Inclua um CompareValidator que garanta que o valor inserido seja um valor inteiro maior ou igual a zero.
  • UnitsOnOrder use uma TextBox cujo ID está definido como NewUnitsOnOrder. Inclua um CompareValidator que garanta que o valor inserido seja um valor inteiro maior ou igual a zero.
  • ReorderLevel use uma TextBox cujo ID está definido como NewReorderLevel. Inclua um CompareValidator que garanta que o valor inserido seja um valor inteiro maior ou igual a zero.
  • Discontinued adicione uma CheckBox, definindo-a IDNewDiscontinuedcomo .
  • CategoryName adicione um DropDownList e defina como IDNewCategoryID. Associe-o a um novo ObjectDataSource chamado CategoriesDataSource e configure-o para usar o CategoriesBLL método da classe s GetCategories() . Fazer com que os s DropDownList ListItem exibam o CategoryName campo de dados, usando o CategoryID campo de dados como seus valores.
  • SupplierName adicione um DropDownList e defina como IDNewSupplierID. Associe-o a um novo ObjectDataSource chamado SuppliersDataSource e configure-o para usar o SuppliersBLL método da classe s GetSuppliers() . Fazer com que os s DropDownList ListItem exibam o CompanyName campo de dados, usando o SupplierID campo de dados como seus valores.

Para cada um dos controles de validação, limpe a ForeColor propriedade para que a FooterStyle cor de primeiro plano branca da classe CSS seja usada no lugar do vermelho padrão. Use também a ErrorMessage propriedade para uma descrição detalhada, mas defina a Text propriedade como um asterisco. Para impedir que o texto do controle de validação cause a quebra automática da interface de inserção em duas linhas, defina a FooterStyle propriedade s Wrap como false para cada um dos FooterTemplate s que usam um controle de validação. Por fim, adicione um controle ValidationSummary abaixo do GridView e defina sua ShowMessageBox propriedade como true e sua ShowSummary propriedade como false.

Ao adicionar um novo produto, precisamos fornecer o e SupplierIDo CategoryID . Essas informações são capturadas por meio de DropDownLists nas células de rodapé dos CategoryName campos e SupplierName . Optei por usar esses campos em oposição aos CategoryID campos e SupplierID TemplateFields porque, nas linhas de dados da grade, o usuário provavelmente está mais interessado em ver os nomes de categoria e fornecedor em vez de seus valores de ID. Como os CategoryID valores e SupplierID agora estão sendo capturados nas CategoryName interfaces de inserção do campo e SupplierName , podemos remover os CategoryID TemplateFields e SupplierID do GridView.

Da mesma forma, o ProductID não é usado ao adicionar um novo produto, portanto, o ProductID TemplateField também pode ser removido. No entanto, vamos deixar o ProductID campo na grade. Além dos controles TextBoxes, DropDownLists, CheckBoxes e validação que compõem a interface de inserção, também precisaremos de um botão Adicionar que, quando clicado, execute a lógica para adicionar o novo produto ao banco de dados. Na Etapa 4, incluiremos um botão Adicionar na interface de inserção no ProductID TemplateField s FooterTemplate.

Fique à vontade para melhorar a aparência dos vários campos gridView. Por exemplo, talvez você queira formatar os UnitPrice valores como uma moeda, alinhar à direita os UnitsInStockcampos , UnitsOnOrdere ReorderLevel e atualizar os HeaderText valores para TemplateFields.

Depois de criar a quantidade de interfaces de inserção nos FooterTemplate s, remover o SupplierID, e CategoryID TemplateFields e melhorar a estética da grade por meio da formatação e do alinhamento de TemplateFields, a marcação declarativa do GridView deve ser semelhante à seguinte:

<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>

Quando exibida por meio de um navegador, a linha de rodapé do GridView agora inclui a interface de inserção concluída (consulte a Figura 10). Neste ponto, a interface de inserção não inclui um meio para o usuário indicar que inseriu os dados do novo produto e deseja inserir um novo registro no banco de dados. Além disso, ainda não abordamos como os dados inseridos no rodapé serão convertidos em um novo registro no Products banco de dados. Na Etapa 4, veremos como incluir um botão Adicionar à interface de inserção e como executar código no postback quando ele for clicado. A etapa 5 mostra como inserir um novo registro usando os dados do rodapé.

O rodapé GridView fornece uma interface para adicionar um novo registro

Figura 10: o rodapé GridView fornece uma interface para adicionar um novo registro (clique para exibir a imagem em tamanho real)

Etapa 4: incluindo um botão Adicionar na interface de inserção

Precisamos incluir um botão Adicionar em algum lugar na interface de inserção, pois a interface de inserção da linha de rodapé atualmente não tem os meios para o usuário indicar que concluiu a inserção das informações do novo produto. Isso pode ser colocado em um dos s existentes FooterTemplate ou podemos adicionar uma nova coluna à grade para essa finalidade. Para este tutorial, vamos colocar o botão Adicionar no ProductID TemplateField s FooterTemplate.

Na Designer, clique no link Editar Modelos na marca inteligente GridView e escolha o ProductID campo s FooterTemplate na lista suspensa. Adicione um controle Web Button (ou um LinkButton ou ImageButton, se preferir) ao modelo, definindo sua ID AddProductcomo , como CommandName Insert e sua Text propriedade como Adicionar, conforme mostrado na Figura 11.

Colocar o botão Adicionar no ProductID TemplateField s FooterTemplate

Figura 11: Colocar o botão Adicionar no ProductID campo modelo (FooterTemplateclique para exibir a imagem em tamanho real)

Depois de incluir o botão Adicionar, teste a página em um navegador. Observe que, ao clicar no botão Adicionar com dados inválidos na interface de inserção, o postback é curto-circuito e o controle ValidationSummary indica os dados inválidos (consulte a Figura 12). Com os dados apropriados inseridos, clicar no botão Adicionar causa um postback. No entanto, nenhum registro é adicionado ao banco de dados. Precisaremos escrever um pouco de código para realmente executar a inserção.

O postback do botão Adicionar será curto-circuito se houver dados inválidos na interface de inserção

Figura 12: o postback do botão Adicionar será curto-circuito se houver dados inválidos na interface de inserção (clique para exibir a imagem em tamanho real)

Observação

Os controles de validação na interface de inserção não foram atribuídos a um grupo de validação. Isso funciona bem desde que a interface de inserção seja o único conjunto de controles de validação na página. Se, no entanto, houver outros controles de validação na página (como controles de validação na interface de edição da grade), os controles de validação na interface de inserção e as propriedades do ValidationGroup botão Adicionar devem receber o mesmo valor para associar esses controles a um grupo de validação específico. Consulte Dissecar os controles de validação no ASP.NET 2.0 para obter mais informações sobre como particionar os controles e botões de validação em uma página em grupos de validação.

Etapa 5: Inserindo um novo registro naProductstabela

Ao utilizar os recursos de edição internos do GridView, o GridView manipula automaticamente todo o trabalho necessário para executar a atualização. Em particular, quando o botão Atualizar é clicado, ele copia os valores inseridos da interface de edição para os parâmetros na coleção objectDataSource e UpdateParameters inicia a atualização invocando o método ObjectDataSource.Update() Como o GridView não fornece essa funcionalidade interna para inserção, devemos implementar o código que chama o método ObjectDataSource e Insert() copia os valores da interface de inserção para a coleção objectDataSource.InsertParameters

Essa lógica de inserção deve ser executada depois que o botão Adicionar for clicado. Conforme discutido no tutorial Adicionando e respondendo a botões em um GridView , sempre que um Button, LinkButton ou ImageButton em um GridView é clicado, o evento gridView é RowCommand acionado no postback. Esse evento aciona se Button, LinkButton ou ImageButton foi adicionado explicitamente, como o botão Adicionar na linha do rodapé ou se foi adicionado automaticamente pelo GridView (como o LinkButtons na parte superior de cada coluna quando Habilitar Classificação está selecionado ou o LinkButtons na interface de paginação quando Habilitar Paginação está selecionado).

Portanto, para responder ao usuário clicando no botão Adicionar, precisamos criar um manipulador de eventos para o evento GridView s RowCommand . Como esse evento é acionado sempre que qualquer Button, LinkButton ou ImageButton no GridView é clicado, é vital que continuemos apenas com a lógica de inserção se a CommandName propriedade passada para o manipulador de eventos for mapeada para o CommandName valor do botão Adicionar ( Inserir ). Além disso, também devemos continuar somente se os controles de validação relatarem dados válidos. Para acomodar isso, crie um manipulador de eventos para o RowCommand evento com o seguinte código:

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...
    }
}

Observação

Talvez você esteja se perguntando por que o manipulador de eventos incomoda ao verificar a Page.IsValid propriedade. Afinal, o postback não será suprimido se dados inválidos forem fornecidos na interface de inserção? Essa suposição está correta desde que o usuário não tenha desabilitado o JavaScript ou tenha tomado medidas para contornar a lógica de validação do lado do cliente. Em suma, nunca se deve depender estritamente da validação do lado do cliente; um marcar do lado do servidor para validade sempre deve ser executado antes de trabalhar com os dados.

Na Etapa 1, criamos o ProductsDataSource ObjectDataSource de modo que seu Insert() método seja mapeado para o ProductsBLL método da classe s AddProduct . Para inserir o novo registro na Products tabela, podemos simplesmente invocar o método objectDataSource: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();
    }
}

Agora que o Insert() método foi invocado, tudo o que resta é copiar os valores da interface de inserção para os parâmetros passados para o ProductsBLL método da classe.AddProduct Como vimos no tutorial Examinando os eventos associados à inserção, atualização e exclusão, isso pode ser feito por meio do evento ObjectDataSource.Inserting Inserting Caso precisemos referenciar programaticamente os controles da linha de Products rodapé do GridView e atribuir seus valores à e.InputParameters coleção. Se o usuário omitir um valor como deixar o ReorderLevel TextBox em branco, precisaremos especificar que o valor inserido no banco de dados deve ser NULL. Como o AddProducts método aceita tipos anuláveis para os campos de banco de dados anuláveis, basta usar um tipo anulável e definir seu valor como null no caso em que a entrada do usuário for omitida.

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;
}

Com o Inserting manipulador de eventos concluído, novos registros podem ser adicionados à tabela de Products banco de dados por meio da linha de rodapé do GridView. Vá em frente e tente adicionar vários novos produtos.

Aprimorando e personalizando a operação de adição

Atualmente, clicar no botão Adicionar adiciona um novo registro à tabela de banco de dados, mas não fornece nenhum tipo de comentário visual que o registro tenha sido adicionado com êxito. O ideal é que um controle Da Web de Rótulo ou uma caixa de alerta do lado do cliente informe ao usuário que sua inserção foi concluída com êxito. Eu deixo isso como um exercício para o leitor.

O GridView usado neste tutorial não aplica nenhuma ordem de classificação aos produtos listados, nem permite que o usuário final classifique os dados. Consequentemente, os registros são ordenados como estão no banco de dados pelo campo de chave primária. Como cada novo registro tem um ProductID valor maior que o último, sempre que um novo produto é adicionado, ele é abordado no final da grade. Portanto, talvez você queira enviar automaticamente o usuário para a última página do GridView depois de adicionar um novo registro. Isso pode ser feito adicionando a seguinte linha de código após a chamada para ProductsDataSource.Insert() no RowCommand manipulador de eventos para indicar que o usuário precisa ser enviado para a última página depois de associar os dados ao GridView:

// Indicate that the user needs to be sent to the last page
SendUserToLastPage = true;

SendUserToLastPage é uma variável booliana no nível da página que é inicialmente atribuída a um valor de false. No manipulador de eventos gridView, DataBound se SendUserToLastPage for false, a PageIndex propriedade será atualizada para enviar o usuário para a última página.

protected void Products_DataBound(object sender, EventArgs e)
{
    // Send user to last page of data, if needed
    if (SendUserToLastPage)
        Products.PageIndex = Products.PageCount - 1;
}

O motivo pelo qual a PageIndex propriedade é definida no DataBound manipulador de eventos (em oposição ao RowCommand manipulador de eventos) é porque quando o RowCommand manipulador de eventos é acionado, ainda não adicionamos o novo registro à tabela de Products banco de dados. Portanto, no RowCommand manipulador de eventos, o último índice de página (PageCount - 1) representa o último índice de página antes de o novo produto ter sido adicionado. Para a maioria dos produtos que estão sendo adicionados, o índice da última página é o mesmo depois de adicionar o novo produto. Mas quando o produto adicionado resultar em um novo índice de última página, se atualizarmos incorretamente o PageIndex no RowCommand manipulador de eventos, seremos levados para a segunda para a última página (o último índice de página antes de adicionar o novo produto) em vez do novo índice da última página. Como o DataBound manipulador de eventos é acionado após a adição do novo produto e a recuperação de dados para a grade, definindo a PageIndex propriedade lá, sabemos que estamos obtendo o índice correto da última página.

Por fim, o GridView usado neste tutorial é bastante amplo devido ao número de campos que devem ser coletados para adicionar um novo produto. Devido a essa largura, um layout vertical do DetailsView pode ser preferencial. A largura geral do GridView pode ser reduzida coletando menos entradas. Talvez não seja necessário coletar os UnitsOnOrdercampos , UnitsInStocke ReorderLevel ao adicionar um novo produto; nesse caso, esses campos podem ser removidos do GridView.

Para ajustar os dados coletados, podemos usar uma das duas abordagens:

  • Continue a usar o AddProduct método que espera valores para os UnitsOnOrdercampos , UnitsInStocke ReorderLevel . Inserting No manipulador de eventos, forneça valores padrão embutidos em código a serem usados para essas entradas que foram removidas da interface de inserção.
  • Crie uma nova sobrecarga do AddProduct método na ProductsBLL classe que não aceita entradas para os UnitsOnOrdercampos , UnitsInStocke ReorderLevel . Em seguida, na página ASP.NET, configure o ObjectDataSource para usar essa nova sobrecarga.

Qualquer uma das opções funcionará igualmente também. Em tutoriais anteriores, usamos a última opção, criando várias sobrecargas para o ProductsBLL método da classe s UpdateProduct .

Resumo

O GridView não tem os recursos de inserção internos encontrados no DetailsView e no FormView, mas com um pouco de esforço, uma interface de inserção pode ser adicionada à linha de rodapé. Para exibir a linha de rodapé em um GridView, basta definir sua ShowFooter propriedade como true. O conteúdo da linha de rodapé pode ser personalizado para cada campo convertendo o campo em um TemplateField e adicionando a interface de inserção ao FooterTemplate. Como vimos neste tutorial, o FooterTemplate pode conter Botões, TextBoxes, DropDownLists, CheckBoxes, controles de fonte de dados para preencher controles da Web controlados por dados (como DropDownLists) e controles de validação. Juntamente com os controles para coletar a entrada do usuário, um Botão Adicionar, LinkButton ou ImageButton é necessário.

Quando o botão Adicionar é clicado, o método objectDataSource é Insert() invocado para iniciar o fluxo de trabalho de inserção. O ObjectDataSource chamará o método insert configurado (o ProductsBLL método de classe s AddProduct , neste tutorial). Devemos copiar os valores da interface de inserção gridView para a coleção ObjectDataSource antes InsertParameters do método insert ser invocado. Isso pode ser feito referenciando programaticamente os controles da Web da interface de inserção no manipulador de eventos objectDataSource.Inserting

Este tutorial conclui nossas técnicas para aprimorar a aparência do GridView. O próximo conjunto de tutoriais examinará como trabalhar com dados binários, como imagens, PDFs, documentos Word e assim por diante e os controles da Web de dados.

Programação feliz!

Sobre o autor

Scott Mitchell, autor de sete livros do ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias da Microsoft Web desde 1998. Scott trabalha como consultor independente, treinador e escritor. Seu último livro é Sams Teach Yourself ASP.NET 2.0 em 24 Horas. Ele pode ser contatado em mitchell@4GuysFromRolla.com. ou através de seu blog, que pode ser encontrado em http://ScottOnWriting.NET.

Agradecimentos Especiais

Esta série de tutoriais foi revisada por muitos revisores úteis. A revisora principal deste tutorial foi Berne Leigh. Interessado em revisar meus próximos artigos do MSDN? Nesse caso, deixe-me uma linha em mitchell@4GuysFromRolla.com.