Observação
O acesso a essa página exige autorização. Você pode tentar entrar ou alterar diretórios.
O acesso a essa página exige autorização. Você pode tentar alterar os diretórios.
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 Web GridView, DetailsView e FormView incluem recursos internos de modificação de dados. Quando usados com controles de fonte de dados declarativos, esses três controles 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, 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 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, examinaremos a adição da 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é.
Figura 1: A linha de 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, vamos primeiro nos concentrar em adicionar um GridView à página que lista os produtos no banco de dados. Comece abrindo a InsertThroughFooter.aspxEnhancedGridView página na pasta e arraste um GridView da Caixa de Ferramentas para o Designer, definindo a propriedade do GridView ID como Products. Em seguida, use a marca inteligente do GridView para associá-la a um novo ObjectDataSource chamado ProductsDataSource.
Figura 2: Criar um Novo ObjectDataSource Nomeado ProductsDataSource (Clique para exibir imagem em tamanho real)
Configure o ObjectDataSource para usar o ProductsBLL método da classe para recuperar informações do GetProducts() produto. Para este tutorial, vamos nos concentrar estritamente em adicionar recursos de inserção e não nos preocupar com edição e exclusão. Portanto, certifique-se de que a lista suspensa na guia INSERT esteja definida como AddProduct() e que as listas suspensas nas guias UPDATE e DELETE estejam definidas como (Nenhum) .
Figura 3: Mapear o AddProduct método para o método do Insert() ObjectDataSource (clique para exibir a imagem em tamanho completo)
Figura 4: Defina as guias Drop-Down listas UPDATE e DELETE 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. Mais adiante neste tutorial, voltaremos e removeremos alguns dos campos cujos valores não precisam ser especificados ao adicionar um novo registro.
Como existem cerca de 80 produtos no banco de dados, o 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, basta marcar a caixa de seleção Habilitar Paginação da marca inteligente do GridView.
Neste ponto, a marcação declarativa do GridView e ObjectDataSource deve ser semelhante ao 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 exibir a imagem em tamanho real)
Etapa 2: adicionar 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 do GridView s ShowHeader e ShowFooter propriedades. Para mostrar a linha de rodapé, basta definir a ShowFooter propriedade como True. Como a Figura 6 ilustra, definir a ShowFooter propriedade como True adiciona uma linha de rodapé à grade.
Figura 6: Para exibir a linha de rodapé, defina ShowFooter como True (clique para exibir a imagem em tamanho real)
Observe que a linha de 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 arquivo configura a FooterStyle propriedade de forma que use a FooterStyle classe CSS. A FooterStyle classe é definida da Styles.css seguinte forma:
.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 resumidas no rodapé do GridView para obter uma atualização.
Depois de definir a ShowFooter propriedade como True, reserve um momento para exibir a saída em um navegador. Atualmente, a linha de rodapé não contém nenhum texto ou controles 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 da interface de paginação (clique para exibir a imagem em tamanho real)
Etapa 3: Personalizando a linha de rodapé
De volta ao tutorial Usando TemplateFields no Controle GridView , vimos como personalizar bastante 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 da linha de rodapé. Portanto, podemos adicionar os controles 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 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 ItemTemplateno EditItemTemplate . Resumindo, 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 oferece suporte à 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 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 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 Editar Modelos na marca inteligente do GridView. Em seguida, na lista suspensa, selecione o campo apropriado e FooterTemplate arraste o controle apropriado da Caixa de Ferramentas para o Designer.
Figura 9: Adicionar a interface de inserção apropriada a cada campo (FooterTemplateclique para exibir a imagem em tamanho real)
A lista com marcadores a seguir enumera os campos GridView, especificando a interface de inserção a ser adicionada:
-
ProductIDnenhum. -
ProductNameadicione um TextBox e defina-oIDcomoNewProductName. Adicione um controle RequiredFieldValidator também para garantir que o usuário insira um valor para o nome do novo produto. -
SupplierIDnenhum. -
CategoryIDnenhum. -
QuantityPerUnitadicione um TextBox, definindo seuIDcomoNewQuantityPerUnit. -
UnitPriceadicione um TextBox chamadoNewUnitPricee um CompareValidator que garanta que o valor inserido seja um valor de moeda maior ou igual a zero. -
UnitsInStockuse um TextBox cujoIDé definido comoNewUnitsInStock. Inclua um CompareValidator que garanta que o valor inserido seja um valor inteiro maior ou igual a zero. -
UnitsOnOrderuse um TextBox cujoIDé definido comoNewUnitsOnOrder. Inclua um CompareValidator que garanta que o valor inserido seja um valor inteiro maior ou igual a zero. -
ReorderLeveluse um TextBox cujoIDé definido comoNewReorderLevel. Inclua um CompareValidator que garanta que o valor inserido seja um valor inteiro maior ou igual a zero. -
Discontinuedadicione uma CheckBox, definindo suaIDcomoNewDiscontinued. -
CategoryNameadicione um DropDownList e defina comoIDNewCategoryID. Associe-o a um novo ObjectDataSource nomeadoCategoriesDataSourcee configure-o para usar oCategoriesBLLmétodo daGetCategories()classe. Faça com que o DropDownList exiba o campo deListItemdados, usando oCategoryNamecampo de dados como seusCategoryIDvalores. -
SupplierNameadicione um DropDownList e defina comoIDNewSupplierID. Associe-o a um novo ObjectDataSource nomeadoSuppliersDataSourcee configure-o para usar oSuppliersBLLmétodo daGetSuppliers()classe. Faça com que o DropDownList exiba o campo deListItemdados, usando oCompanyNamecampo de dados como seusSupplierIDvalores.
Para cada um dos controles de validação, desmarque a ForeColor propriedade para que a FooterStyle cor branca do primeiro plano da classe CSS seja usada no lugar 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 impedir que o texto do controle de validação faça com que a interface de inserção seja encapsulada 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 CategoryID e SupplierID. 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 vez de CategoryID e SupplierID TemplateFields porque nas linhas de dados da grade o usuário provavelmente está mais interessado em ver os nomes das categorias e dos fornecedores do que seus valores de ID. Como os CategoryID valores and SupplierID agora estão sendo capturados nas CategoryName interfaces de inserção do campo and SupplierName , podemos remover o CategoryID e SupplierID TemplateFields 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 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 .FooterTemplate
Sinta-se à vontade para melhorar a aparência dos vários campos do 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 os TemplateFields.
Depois de criar a série de inserir interfaces no FooterTemplate s, remover o SupplierID, e CategoryID TemplateFields e melhorar a estética da grade por meio da formatação e alinhamento do 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 traduzidos 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 o código no postback quando ele for 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 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 esse fim. Para este tutorial, vamos colocar o botão Adicionar no ProductID TemplateField .FooterTemplate
No Designer, clique no link Editar Modelos na marca inteligente do GridView e escolha o ProductID campo na FooterTemplate lista suspensa. Adicione um controle Web Button (ou um LinkButton ou ImageButton, se preferir) ao modelo, definindo sua ID como AddProduct, its CommandName como Insert e sua Text propriedade como Add, conforme mostrado na Figura 11.
Figura 11: Coloque o botão Adicionar no TemplateField (ProductIDFooterTemplate 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 Add with invalid data na interface de inserção, o postback entra em 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 realizar a inserção.
Figura 12: O postback do botão Adicionar está em 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 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 Atualizar é clicado, ele copia os valores inseridos da interface de edição para os parâmetros na coleção do ObjectDataSource UpdateParameters e inicia a atualização invocando o método do ObjectDataSource Update() . 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 InsertParameters ObjectDataSource.
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 do 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 o LinkButtons na parte superior de cada coluna quando Habilitar Classificação é selecionado ou o LinkButtons na interface de paginação quando Habilitar Paginação é selecionado).
Portanto, para responder ao usuário clicando no botão Adicionar, precisamos criar um manipulador de RowCommand eventos para o evento do GridView. Como esse evento é acionado sempre que qualquer Button, LinkButton ou ImageButton no GridView é clicado, é vital que só prossigamos 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 ( 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 Sub Products_RowCommand(sender As Object, e As GridViewCommandEventArgs) _
Handles Products.RowCommand
' Insert data if the CommandName == "Insert"
' and the validation controls indicate valid data...
If e.CommandName = "Insert" AndAlso Page.IsValid Then
' TODO: Insert new record...
End If
End Sub
Observação
Você pode estar se perguntando por que o manipulador de eventos se preocupa 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 desabilitado 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 do lado do servidor deve sempre ser executada 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 AddProduct classe. Para inserir o novo registro na Products tabela, podemos simplesmente invocar o método ObjectDataSource Insert() :
Protected Sub Products_RowCommand(sender As Object, e As GridViewCommandEventArgs) _
Handles Products.RowCommand
' Insert data if the CommandName == "Insert"
' and the validation controls indicate valid data...
If e.CommandName = "Insert" AndAlso Page.IsValid Then
' Insert new record
ProductsDataSource.Insert()
End If
End Sub
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 AddProduct classe. Como vimos no Examinando os eventos associados à inserção, atualização e exclusão tutorial, isso pode ser feito por meio do Inserting evento ObjectDataSource. Caso precisemos Inserting referenciar programaticamente os controles da linha de rodapé do Products GridView e atribuir 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 como Nothing no caso em que a entrada do usuário é omitida.
Protected Sub ProductsDataSource_Inserting _
(sender As Object, e As .ObjectDataSourceMethodEventArgs) _
Handles ProductsDataSource.Inserting
' Programmatically reference Web controls in the inserting interface...
Dim NewProductName As TextBox = _
Products.FooterRow.FindControl("NewProductName")
Dim NewCategoryID As DropDownList = _
Products.FooterRow.FindControl("NewCategoryID")
Dim NewSupplierID As DropDownList = _
Products.FooterRow.FindControl("NewSupplierID")
Dim NewQuantityPerUnit As TextBox = _
Products.FooterRow.FindControl("NewQuantityPerUnit")
Dim NewUnitPrice As TextBox = _
Products.FooterRow.FindControl("NewUnitPrice")
Dim NewUnitsInStock As TextBox = _
Products.FooterRow.FindControl("NewUnitsInStock")
Dim NewUnitsOnOrder As TextBox = _
Products.FooterRow.FindControl("NewUnitsOnOrder")
Dim NewReorderLevel As TextBox = _
Products.FooterRow.FindControl("NewReorderLevel")
Dim NewDiscontinued As CheckBox = _
Products.FooterRow.FindControl("NewDiscontinued")
' Set the ObjectDataSource's InsertParameters values...
e.InputParameters("productName") = NewProductName.Text
e.InputParameters("supplierID") = _
Convert.ToInt32(NewSupplierID.SelectedValue)
e.InputParameters("categoryID") = _
Convert.ToInt32(NewCategoryID.SelectedValue)
Dim quantityPerUnit As String = Nothing
If Not String.IsNullOrEmpty(NewQuantityPerUnit.Text) Then
quantityPerUnit = NewQuantityPerUnit.Text
End If
e.InputParameters("quantityPerUnit") = quantityPerUnit
Dim unitPrice As Nullable(Of Decimal) = Nothing
If Not String.IsNullOrEmpty(NewUnitPrice.Text) Then
unitPrice = Convert.ToDecimal(NewUnitPrice.Text)
End If
e.InputParameters("unitPrice") = unitPrice
Dim unitsInStock As Nullable(Of Short) = Nothing
If Not String.IsNullOrEmpty(NewUnitsInStock.Text) Then
unitsInStock = Convert.ToInt16(NewUnitsInStock.Text)
End If
e.InputParameters("unitsInStock") = unitsInStock
Dim unitsOnOrder As Nullable(Of Short) = Nothing
If Not String.IsNullOrEmpty(NewUnitsOnOrder.Text) Then
unitsOnOrder = Convert.ToInt16(NewUnitsOnOrder.Text)
End If
e.InputParameters("unitsOnOrder") = unitsOnOrder
Dim reorderLevel As Nullable(Of Short) = Nothing
If Not String.IsNullOrEmpty(NewReorderLevel.Text) Then
reorderLevel = Convert.ToInt16(NewReorderLevel.Text)
End If
e.InputParameters("reorderLevel") = reorderLevel
e.InputParameters("discontinued") = NewDiscontinued.Checked
End Sub
Com o manipulador de Inserting 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 do banco de dados, mas não fornece nenhum tipo de feedback visual de que o registro foi adicionado com êxito. Idealmente, um controle Web de rótulo ou uma caixa de alerta do lado do cliente informaria 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 por seu campo de chave primária. Como cada novo registro tem um ProductID valor maior que o anterior, toda vez que um novo produto é adicionado, ele é anexado ao 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 no ProductsDataSource.Insert()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 booleana de nível de página à qual é atribuído inicialmente um valor de False. No manipulador de eventos do DataBound GridView, se SendUserToLastPage for false, a PageIndex propriedade será atualizada para enviar o usuário para a última página.
Protected Sub Products_DataBound(sender As Object, e As EventArgs) _
Handles Products.DataBound
' Send user to last page of data, if needed
If SendUserToLastPage Then
Products.PageIndex = Products.PageCount - 1
End If
End Sub
O motivo pelo qual a PageIndex propriedade é definida no manipulador de DataBound eventos (em oposição ao manipulador de RowCommand eventos) é porque, quando o RowCommand manipulador de eventos é acionado, ainda não adicionamos o novo registro à tabela do Products banco de dados. Portanto, no manipulador de RowCommand eventos, o último índice de página (PageCount - 1) representa o último índice de página antes da adição do novo produto. 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 de última página, se atualizarmos incorretamente o PageIndexRowCommand no manipulador de eventos, seremos levados para a penú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 depois que o novo produto é adicionado e os dados são recuperados para a grade, ao definir 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 preferido. A largura geral do GridView pode ser reduzida coletando menos entradas. Talvez não precisemos coletar os UnitsOnOrdercampos , UnitsInStocke ao ReorderLevel adicionar um novo produto, caso em que esses campos podem ser removidos do GridView.
Para ajustar os dados coletados, podemos usar uma das duas abordagens:
- Continue a usar o
AddProductmétodo que espera valores para osUnitsOnOrdercampos ,UnitsInStocke .ReorderLevelInsertingNo 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
AddProductmétodo naProductsBLLclasse que não aceita entradas para osUnitsOnOrdercampos ,UnitsInStockeReorderLevel. Em seguida, na página ASP.NET, configure o ObjectDataSource para usar essa nova sobrecarga.
Qualquer uma das opções funcionará igualmente bem. 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 possui 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 Buttons, TextBoxes, DropDownLists, CheckBoxes, controles de fonte de dados para preencher controles Web controlados por dados (como DropDownLists) e controles de validação. Juntamente com os controles para coletar a entrada do usuário, é necessário um Adicionar Botão, LinkButton ou ImageButton.
Quando o botão Adicionar é clicado, o método do Insert() ObjectDataSource é invocado para iniciar o fluxo de trabalho de inserção. Em seguida, o ObjectDataSource chamará o método de inserção configurado (o ProductsBLL método da AddProduct classe, neste tutorial). Devemos copiar os valores da interface de inserção do GridView para a coleção do ObjectDataSource antes que InsertParameters o método de inserção seja invocado. Isso pode ser feito referenciando programaticamente os controles Web da interface de inserção no manipulador de Inserting eventos do ObjectDataSource.
Este tutorial conclui nossa análise das 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 do Word e assim por diante, e os controles da Web de dados.
Divirta-se programando!
Sobre o autor
Scott Mitchell, autor de sete livros 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 alcançado em mitchell@4GuysFromRolla.com.
Agradecimentos Especiais a
Esta série de tutoriais foi revisada por muitos revisores úteis. A revisora principal deste tutorial foi Bernadette Leigh. Interessado em revisar meus próximos artigos do MSDN? Se assim for, deixe-me uma linha em mitchell@4GuysFromRolla.com.