Nota
O acesso a esta página requer autorização. Podes tentar iniciar sessão ou mudar de diretório.
O acesso a esta página requer autorização. Podes tentar mudar de diretório.
por Scott Mitchell
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 da inserção, atualização e exclusão de dados , os controles da 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 rápida e facilmente configurados para modificar dados - e em cenários sem a necessidade de escrever uma única linha de código. Infelizmente, apenas 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 esforço, podemos adaptar 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é para cada coluna inclui o elemento apropriado da interface do usuário de coleta de dados (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é.
Figura 1: A linha de rodapé fornece uma interface para adicionar novos produtos (Clique para visualizar a imagem em tamanho real)
Etapa 1: Exibindo informações do produto em um GridView
Antes de nos preocuparmos em criar a interface de inserção no rodapé do GridView, vamos primeiro nos concentrar em adicionar um GridView à página que lista os produtos no banco de dados. Comece por abrir a página InsertThroughFooter.aspx na pasta EnhancedGridView e arraste um GridView da Caixa de Ferramentas para o Designer, definindo a propriedade ID do GridView como Products. Em seguida, use o smart tag do GridView para vinculá-lo a um novo ObjectDataSource chamado ProductsDataSource.
Figura 2: Criar um novo ObjectDataSource nomeado ProductsDataSource (Clique para visualizar a imagem em tamanho real)
Configure o ObjectDataSource para usar o método da classe ProductsBLLGetProducts() para recuperar informações do produto. Para este tutorial, vamos nos concentrar estritamente em adicionar recursos de inserção e não se preocupar com a edição e exclusão. Portanto, certifique-se de que a lista suspensa no separador INSERIR está definida como AddProduct() e que as listas suspensas nos separadores ATUALIZAR e ELIMINAR estão definidas como (Nenhum).
Figura 3: Mapear o AddProduct método para o método ObjectDataSource s Insert() (Clique para visualizar a imagem em tamanho real)
Figura 4: Configure as guias UPDATE e DELETE da lista Drop-Down para (Nenhum) (Clique para visualizar a imagem em tamanho real)
Depois de concluir o assistente Configurar Fonte de Dados de 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. Mais adiante 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 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, simplesmente marque a caixa de seleção Permitir paginação na etiqueta inteligente do 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>
Figura 5: Todos os campos de dados do produto são exibidos em um GridView paginado (Clique para visualizar a imagem em tamanho real)
Etapa 2: Adicionando uma linha de rodapé
Junto com suas linhas de cabeçalho e dados, o GridView inclui uma linha de rodapé. As linhas de cabeçalho e rodapé são exibidas dependendo dos valores das s ShowHeader e ShowFooter propriedades de GridView. Para mostrar a linha de rodapé, basta definir a ShowFooter propriedade como true. Como ilustra a Figura 6, ao definir a propriedade ShowFooter como true, adiciona-se uma linha de rodapé à grelha.
Figura 6: Para exibir a linha de rodapé, defina ShowFooter como True (Clique para visualizar a imagem em tamanho normal)
Observe que a linha do rodapé tem uma cor de fundo vermelha escura. Isso se deve ao tema DataWebControls que criamos e aplicamos a todas as páginas no tutorial Exibindo dados com o ObjectDataSource . Especificamente, o GridView.skin ficheiro configura a FooterStyle propriedade de forma a utilizar a FooterStyle classe CSS. A FooterStyle classe é definida da seguinte forma Styles.css :
.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 novamente o tutorial Exibindo informações de resumo no Rodapé do GridView para obter uma atualização.
Depois de definir a ShowFooter propriedade como true, reserve um momento para visualizar a saída em um navegador. Atualmente, a linha de 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.
Figura 7: A linha de rodapé vazia é exibida acima dos controles de interface de paginação (Clique para visualizar a imagem em tamanho real)
Etapa 3: Personalizando a linha de rodapé
De volta ao tutorial Usando TemplateFields no controle GridView , vimos como personalizar muito a exibição de uma coluna GridView específica usando TemplateFields (em oposição a BoundFields ou CheckBoxFields); em Personalizando a interface de modificação de dados , examinamos o uso de 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 EditItemTemplate, o TemplateField também inclui um FooterTemplate que especifica o conteúdo para a linha de rodapé. Portanto, podemos adicionar os controlos web necessários para a interface de inserção de cada campo no FooterTemplate. Para começar, converta todos os campos no GridView em TemplateFields. Isso pode ser feito clicando no link Editar colunas na marca inteligente do GridView, selecionando cada campo no canto inferior esquerdo e clicando no link Converter este campo em um TemplateField.
Figura 8: Converter cada campo em um TemplateField
Clicar em 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 com 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 no seguinte código 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 desativado). O BoundField ProductID de leitura apenas foi convertido em um TemplateField com um controle de etiqueta no ItemTemplate e no EditItemTemplate. Em resumo, 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 funcionalidade do campo existente.
Como o GridView com o qual estamos trabalhando não suporta edição, sinta-se à vontade para remover o EditItemTemplate de cada TemplateField, deixando apenas o ItemTemplate. Depois de fazer isso, a marcação declarativa do GridView deve ter a seguinte aparência:
<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 (ProductID, por exemplo), outros variarão nos controles da Web usados para coletar as informações do novo produto.
Para criar a interface de edição, escolha o link Modelos de Edição na etiqueta inteligente do GridView. Em seguida, na lista suspensa, selecione os campos apropriados FooterTemplate e arraste o controle apropriado da Caixa de Ferramentas para o Designer.
Figura 9: Adicionar a interface de inserção apropriada a cada campo s FooterTemplate (Clique para visualizar a imagem em tamanho real)
A lista com marcadores a seguir enumera os campos GridView, especificando a interface de inserção a ser adicionada:
-
ProductIDnenhuma. -
ProductNameadicione um TextBox e defina seuIDcomoNewProductName. Adicione também um controle RequiredFieldValidator para garantir que o usuário insira um valor para o nome do novo produto. -
SupplierIDnenhuma. -
CategoryIDnenhuma. -
QuantityPerUnitadicione um TextBox, definindo seuIDcomoNewQuantityPerUnit. -
UnitPriceadicione um TextBox nomeadoNewUnitPricee um CompareValidator que garante que o valor inserido seja um valor de moeda maior ou igual a zero. -
UnitsInStockutilize um TextBox onde oIDestá definido comoNewUnitsInStock. Inclua um CompareValidator que garante que o valor inserido seja um valor inteiro maior ou igual a zero. -
UnitsOnOrderutilize um TextBox onde oIDestá definido comoNewUnitsOnOrder. Inclua um CompareValidator que garante que o valor inserido seja um valor inteiro maior ou igual a zero. -
ReorderLevelutilize um TextBox onde oIDestá definido comoNewReorderLevel. Inclua um CompareValidator que garante que o valor inserido seja um valor inteiro maior ou igual a zero. -
Discontinuedadicione uma CheckBox, definindo suaIDcomoNewDiscontinued. -
CategoryNameadicione um DropDownList e defina seuIDcomoNewCategoryID. Associe-o a um novo ObjectDataSource chamadoCategoriesDataSourcee configure-o para usar o métodoCategoriesBLLda classeGetCategories(). Faça com que o DropDownList sListItemexiba oCategoryNamecampo de dados, usando oCategoryIDcampo de dados como seus valores. -
SupplierNameadicione um DropDownList e defina seuIDcomoNewSupplierID. Associe-o a um novo ObjectDataSource chamadoSuppliersDataSourcee configure-o para usar o métodoSuppliersBLLda classeGetSuppliers(). Faça com que o DropDownList sListItemexiba oCompanyNamecampo de dados, usando oSupplierIDcampo de dados como seus valores.
Para cada um dos controlos de validação, remova a propriedade ForeColor para que a classe CSS FooterStyle com cor branca no primeiro plano seja usada em vez do vermelho padrão. Use também a ErrorMessage propriedade para obter uma descrição detalhada, mas defina a Text propriedade como um asterisco. Para evitar que o texto do controle de validação faça com que a interface de inserção seja quebrada em duas linhas, defina a propriedade FooterStyle de Wrap como false para cada FooterTemplate que usa um controle de validação. Finalmente, adicione um controle ValidationSummary abaixo de GridView e defina sua ShowMessageBox propriedade como true e sua ShowSummary propriedade como false.
Ao adicionar um novo produto, precisamos fornecer o CategoryID e SupplierID. Essas informações são capturadas através das DropDownLists nas células de rodapé dos CategoryName campos e SupplierName . Optei por usar esses campos em vez de CategoryIDSupplierID e TemplateFields porque nas linhas de dados da grade o usuário provavelmente está mais interessado em ver os nomes de categoria e fornecedor do que seus valores de ID. Como os valores CategoryID e SupplierID agora estão a ser capturados nos campos de inserção das interfaces CategoryName e SupplierName, podemos remover os CamposModelo CategoryID 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 das TextBoxes, DropDownLists, CheckBoxes e controles de validação que compõem a interface de inserção, também precisaremos de um botão Adicionar que, quando clicado, executa 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.
Sinta-se à vontade para melhorar a aparência dos vários campos GridView. Por exemplo, talvez queira formatar os UnitPrice valores como moeda, alinhar à direita os campos UnitsInStock, UnitsOnOrder, e atualizar os valores ReorderLevel, assim como os valores HeaderText para os TemplateFields.
Depois de criar uma variedade de interfaces de inserção nos FooterTemplates, remover os SupplierID e CategoryIDTemplateFields, e aperfeiçoar a estética do grid através da formatação e alinhamento dos CategoryIDTemplateFields, a marcação declarativa do seu 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 visualizada através 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 para o 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é se traduzirão em um novo registro no Products banco de dados. Na Etapa 4, veremos como incluir um botão Adicionar na interface de inserção e como executar código no postback quando ele é clicado. A etapa 5 mostra como inserir um novo registro usando os dados do rodapé.
Figura 10: O rodapé GridView fornece uma interface para adicionar um novo registro (Clique para visualizar 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, uma vez que a interface de inserção da linha de rodapé atualmente não tem os meios de indicar que o usuário concluiu a inserção das informações do novo produto. Isso poderia ser colocado em um dos FooterTemplate existentes ou poderíamos adicionar uma nova coluna à grelha para esse fim. Para este tutorial, vamos colocar o botão Adicionar no ProductID TemplateField s FooterTemplate.
No Designer, clique no link Editar modelos na etiqueta inteligente do GridView e selecione o ProductID campo FooterTemplate na lista suspensa. Adicione um controle Web Button (ou um LinkButton ou ImageButton, se preferir) ao modelo, definindo sua ID como AddProduct, sua CommandName como Insert e sua Text propriedade como Add como mostrado na Figura 11.
Figura 11: Coloque o botão Add no TemplateField s ProductID (FooterTemplate 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-circuitado e o controle ValidationSummary indica os dados inválidos (consulte a Figura 12). Com os dados apropriados inseridos, clicar no botão Adicionar provoca um retorno ao servidor. No entanto, nenhum registro é adicionado ao banco de dados. Precisaremos escrever um pouco de código para realmente realizar a inserção.
Figura 12: O Postback do botão Adicionar é interrompido se houver dados inválidos na interface de inserção de dados (Clique para visualizar 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 Dissecando 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 lida automaticamente com todo o trabalho necessário para executar a atualização. Em particular, quando o botão Update é clicado, ele copia os valores inseridos da interface de edição para os parâmetros na coleção s UpdateParameters ObjectDataSource e inicia a atualização invocando o método s Update() ObjectDataSource. Como o GridView não fornece essa funcionalidade interna para inserção, devemos implementar o código que chama o método do ObjectDataSource Insert() e copia os valores da interface de inserção para a coleção do ObjectDataSource InsertParameters.
Essa lógica de inserção deve ser executada após o botão Adicionar ter sido 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 s GridView RowCommand é acionado no postback. Esse evento é acionado se o Button, LinkButton ou ImageButton foi adicionado explicitamente, como o botão Adicionar na linha de rodapé, ou se foi adicionado automaticamente pelo GridView (como LinkButtons na parte superior de cada coluna quando Enable Sorting está selecionado, ou LinkButtons na interface de paginação quando Enable Paging é selecionado).
Portanto, para responder ao usuário clicando no botão Adicionar, precisamos criar um manipulador de eventos para o evento s GridView RowCommand . Como esse evento é acionado sempre que qualquer Button, LinkButton ou ImageButton no GridView é clicado, é vital que continuemos com a lógica de inserção apenas se a CommandName propriedade passada para o manipulador de eventos for mapeada para o CommandName valor do botão Add ( Insert ). Além disso, também só devemos proceder se os controlos de validação comunicarem 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
Você pode estar se perguntando por que o manipulador de eventos se incomoda em 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 desativado o JavaScript ou tenha tomado medidas para contornar a lógica de validação do lado do cliente. Em suma, nunca se deve confiar estritamente na validação do lado do cliente; Uma verificação de validade no servidor deve ser sempre realizada antes de trabalhar com os dados.
Na Etapa 1, criamos o ProductsDataSource ObjectDataSource de modo que seu Insert() método seja mapeado para o método s ProductsBLL da AddProduct classe. Para inserir o Products novo registro na tabela, podemos simplesmente invocar o método s 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 método Insert() foi invocado, tudo o que resta é copiar os valores da interface de inserção de dados para os parâmetros passados ao método ProductsBLL 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 No caso de precisarmos referenciar programaticamente os controlos da Products linha de rodapé do GridView e atribuir os seus valores à e.InputParameters coleção. Se o usuário omitir um valor, como deixar o ReorderLevel TextBox em branco, precisamos 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 para null no caso em que a entrada do usuário é 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 manipulador de Inserting eventos concluído, novos registros podem ser adicionados à Products tabela do 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 adicionar
Atualmente, clicar no botão Adicionar adiciona um novo registro à tabela do banco de dados, mas não fornece nenhum tipo de feedback visual de que o registro foi adicionado com êxito. Idealmente, um controle Label Web ou uma caixa de alerta do lado do cliente informaria o usuário de que sua inserção foi concluída com sucesso. Deixo isto 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 por seu campo de chave primária. Como cada novo registo tem um ProductID valor maior do que o anterior, sempre que um novo produto é adicionado, ele é colocado no final da grelha. Portanto, você pode querer 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 no ProductsDataSource.Insert()RowCommand manipulador de eventos para indicar que o usuário precisa ser enviado para a última página depois de vincular os dados ao GridView:
// Indicate that the user needs to be sent to the last page
SendUserToLastPage = true;
SendUserToLastPage é uma variável booleana de nível de página à qual é inicialmente atribuído um valor de false. No manipulador de eventos do DataBound GridView, se SendUserToLastPage for falso, a propriedade PageIndex é atualizada para enviar o utilizador 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;
}
A razão pela 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 à Products tabela do banco de dados. Portanto, no manipulador de eventos, o RowCommand índice da última página (PageCount - 1) representa o índice da última página antes do novo produto ter sido adicionado. Para a maioria dos produtos adicionados, o índice da última página é o mesmo após a adição do novo produto. Mas quando o produto adicionado resulta em um novo índice da última página, se atualizarmos incorretamente o PageIndex no manipulador de eventos RowCommand, seremos direcionados para a penúltima página (o índice da última página antes de adicionar o novo produto) em vez de para o novo índice da última página. Dado que o DataBound manipulador de eventos é acionado após a adição do novo produto e os dados são reatualizados na grelha, ao definir a propriedade PageIndex nesse ponto, sabemos que estamos obtendo o índice da última página corretamente.
Finalmente, 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 de DetailsView pode ser preferível. A largura geral do GridView pode ser reduzida coletando menos entradas. Talvez não precisemos coletar os campos UnitsOnOrder, UnitsInStock e ReorderLevel ao adicionar um novo produto, caso em que esses campos poderiam ser removidos do GridView.
Para ajustar os dados recolhidos, podemos utilizar uma de duas abordagens:
- Continue a usar o método
AddProductque espera valores para os camposUnitsOnOrder,UnitsInStockeReorderLevel.InsertingNo manipulador de eventos, forneça valores padrão codificados a serem usados para essas entradas que foram removidas da interface de inserção. - Crie uma nova sobrecarga do método
AddProductna classeProductsBLLque não aceita entradas para os camposUnitsOnOrder,UnitsInStockeReorderLevel. Em seguida, na página ASP.NET, configure o ObjectDataSource para usar essa nova sobrecarga.
Qualquer uma das opções também funcionará da mesma forma. Em tutoriais anteriores, usamos a última opção, criando várias sobrecargas para o ProductsBLL método da UpdateProduct classe.
Resumo
O GridView não tem os recursos internos de inserção 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 Buttons, TextBoxes, DropDownLists, CheckBoxes, controles de fonte de dados para preencher controles da Web controlados por dados (como DropDownLists) e controles de validação. Junto com os controles para coletar a entrada do usuário, um Add Button, LinkButton ou ImageButton é necessário.
Quando o botão Adicionar é clicado, o método do ObjectDataSource é Insert() invocado para iniciar o fluxo de trabalho de inserção. O ObjectDataSource chamará o método de inserção configurado (o método ProductsBLL da classe AddProduct, neste tutorial). Devemos copiar os valores da interface de inserção de GridView para a coleção s InsertParameters ObjectDataSource antes do método insert ser invocado. Isso pode ser feito referenciando programaticamente os controlos Web na interface de inserção, no manipulador de eventos do ObjectDataSource Inserting.
Este tutorial completa nossa análise das técnicas para melhorar a aparência do GridView. O próximo conjunto de tutoriais examinará como trabalhar com dados binários, como imagens, PDFs, documentos do Word e assim por diante e os controles da Web de dados.
Feliz Programação!
Sobre o Autor
Scott Mitchell, autor de sete livros sobre ASP/ASP.NET e fundador da 4GuysFromRolla.com, trabalha com tecnologias Web da Microsoft desde 1998. Scott trabalha como consultor, formador e escritor independente. Seu último livro é Sams Teach Yourself ASP.NET 2.0 in 24 Hours. Ele pode ser contatado em mitchell@4GuysFromRolla.com.
Um agradecimento especial a
Esta série de tutoriais foi revisada por muitos revisores úteis. A principal revisora deste tutorial foi Bernadette Leigh. Interessado em rever meus próximos artigos do MSDN? Se for o caso, envie-me uma mensagem para mitchell@4GuysFromRolla.com.