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
Nas interfaces que criamos até agora, um usuário pode excluir dados acidentalmente clicando no botão Excluir quando quiser clicar no botão Editar. Neste tutorial, adicionaremos uma caixa de diálogo de confirmação do lado do cliente que será exibida quando o botão Excluir for clicado.
Introdução
Nos últimos tutoriais, vimos como usar nossa arquitetura de aplicativo, ObjectDataSource e os controles da Web de dados em conjunto para fornecer recursos de inserção, edição e exclusão. As interfaces de exclusão que examinamos até agora foram compostas por um botão "Excluir" que, quando clicado, causa um postback e invoca o método do ObjectDataSource Delete(). Em seguida, o método invoca o método configurado da Camada de Lógica de Negócios, que propaga a chamada para a Camada de Acesso a Dados, emitindo a instrução real Delete() para o banco de dados.
Embora essa interface do usuário permita que os visitantes excluam registros por meio dos controles GridView, DetailsView ou FormView, ela não tem qualquer tipo de confirmação quando o usuário clica no botão Excluir. Se um usuário clicar acidentalmente no botão Excluir quando quiser clicar em Editar, o registro que ele pretendia atualizar será excluído. Para ajudar a evitar isso, neste tutorial, adicionaremos uma caixa de diálogo de confirmação do lado do cliente que aparece quando o botão Excluir é clicado.
A função JavaScript confirm(string) exibe seu parâmetro de entrada de cadeia de caracteres como o texto dentro de uma caixa de diálogo modal que vem equipada com dois botões – OK e Cancelar (consulte Figura 1). A confirm(string) função retorna um valor booliano dependendo de qual botão é clicado (truese o usuário clicar em OK e false se clicar em Cancelar).
Figura 1: O método JavaScript confirm(string) exibe uma caixa de mensagem modal Client-Side
Durante o envio de um formulário, se um manipulador de eventos do lado do cliente retornar um valor de false, o envio do formulário será cancelado. Usando esse recurso, podemos fazer com que o manipulador de eventos do botão Excluir do lado do cliente onclick retorne o valor de uma chamada para confirm("Are you sure you want to delete this product?"). Se o usuário clicar em Cancelar, confirm(string) retornará false, fazendo com que o envio do formulário seja cancelado. Sem postback, o produto cujo botão Excluir foi clicado não será excluído. Se, no entanto, o usuário clicar em OK na caixa de diálogo de confirmação, o postback ocorrerá normalmente e o produto será excluído. Consulte o uso do método JavaScript confirm() para controlar o envio de formulários para obter mais informações sobre essa técnica.
Adicionar o script do cliente necessário difere ligeiramente quando se utiliza modelos em vez de um campo de comando. Portanto, neste tutorial, examinaremos um exemplo de FormView e GridView.
Observação
O uso de técnicas de confirmação do lado do cliente, como as discutidas neste tutorial, pressupõe que os usuários estão visitando com navegadores que dão suporte a JavaScript e que eles têm o JavaScript habilitado. Se qualquer uma dessas suposições não for verdadeira para um determinado usuário, ao clicar no botão Excluir, ocorrerá imediatamente um postback sem exibir uma caixa de mensagem de confirmação.
Etapa 1: Criando um FormView que dá suporte à exclusão
Comece adicionando um FormView à página ConfirmationOnDelete.aspx na pasta EditInsertDelete, associando-o a um novo ObjectDataSource que recupera as informações do produto por meio do método ProductsBLL da classe GetProducts(). Configure também o ObjectDataSource para que o ProductsBLL método da DeleteProduct(productID) classe seja mapeado para o método ObjectDataSource Delete() ; verifique se as listas suspensas das guias INSERT e UPDATE estão definidas como (Nenhum). Por fim, marque a caixa de seleção "Habilitar Paginação" na smart tag do FormView.
Após estas etapas, a nova marcação declarativa do ObjectDataSource terá a seguinte aparência:
<asp:ObjectDataSource ID="ObjectDataSource1" runat="server"
DeleteMethod="DeleteProduct" OldValuesParameterFormatString="original_{0}"
SelectMethod="GetProducts" TypeName="ProductsBLL">
<DeleteParameters>
<asp:Parameter Name="productID" Type="Int32" />
</DeleteParameters>
</asp:ObjectDataSource>
Como em nossos exemplos anteriores que não usavam concorrência otimista, tire um momento para limpar a propriedade ObjectDataSource OldValuesParameterFormatString.
Como ele foi associado a um controle ObjectDataSource que dá suporte apenas à exclusão, o FormView ItemTemplate oferece apenas o botão Excluir, sem os botões Novo e Atualizar. No entanto, a marcação declarativa do FormView inclui um supérfluo EditItemTemplate e InsertItemTemplateque pode ser removido. Reserve um momento para personalizar o ItemTemplate modo que mostra apenas um subconjunto dos campos de dados do produto. Configurei para que o meu mostre o nome do produto em um título <h3> acima dos nomes do fornecedor e da categoria (juntamente com o botão Excluir).
<asp:FormView ID="FormView1" AllowPaging="True" DataKeyNames="ProductID"
DataSourceID="ObjectDataSource1" runat="server">
<ItemTemplate>
<h3><i><%# Eval("ProductName") %></i></h3>
<b>Category:</b>
<asp:Label ID="CategoryNameLabel" runat="server"
Text='<%# Eval("CategoryName") %>'>
</asp:Label><br />
<b>Supplier:</b>
<asp:Label ID="SupplierNameLabel" runat="server"
Text='<%# Eval("SupplierName") %>'>
</asp:Label><br />
<asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"
CommandName="Delete" Text="Delete">
</asp:LinkButton>
</ItemTemplate>
</asp:FormView>
Com essas alterações, temos uma página da Web totalmente funcional que permite que um usuário alterne os produtos um de cada vez, com a capacidade de excluir um produto simplesmente clicando no botão Excluir. A Figura 2 mostra uma captura de tela do nosso progresso até agora quando exibida por meio de um navegador.
Figura 2: O FormView mostra informações sobre um único produto (clique para exibir a imagem em tamanho real)
Etapa 2: Chamando a função confirm(string) dos Botões de Exclusão no evento de clique Client-Side
Com o FormView criado, a etapa final é configurar o botão Excluir para que, quando ele é clicado pelo visitante, a função JavaScript confirm(string) seja invocada. A adição de script do lado do cliente a um evento onclick de Button, LinkButton ou ImageButton pode ser realizada por meio do uso do OnClientClick property, que é novo no ASP.NET 2.0. Como queremos ter o valor da confirm(string) função retornado, basta definir essa propriedade como: return confirm('Are you certain that you want to delete this product?');
Após essa alteração, a sintaxe declarativa Delete LinkButton deve ser semelhante a:
<asp:LinkButton ID="DeleteButton" runat="server" CausesValidation="False"
CommandName="Delete" Text="Delete"
OnClientClick="return confirm('Are you certain you want to delete this product?');">
</asp:LinkButton>
É só isso! A Figura 3 mostra uma captura de tela dessa confirmação em ação. Clicar no botão Excluir abre a caixa de diálogo de confirmação. Se o usuário clicar em Cancelar, o postback será cancelado e o produto não será excluído. Se, no entanto, o usuário clicar em OK, o postback continuará e o método ObjectDataSource Delete() será invocado, culminando na exclusão do registro de banco de dados.
Observação
A cadeia de caracteres passada para a confirm(string) função JavaScript é delimitada com apóstrofos (em vez de aspas). No JavaScript, as cadeias de caracteres podem ser delimitadas usando qualquer um dos caracteres. Usamos apóstrofos aqui para que os delimitadores para a cadeia de caracteres passada para confirm(string) não introduzam uma ambiguidade com os delimitadores usados para o valor da propriedade OnClientClick.
Figura 3: Uma confirmação agora é exibida ao clicar no botão Excluir (clique para exibir a imagem em tamanho real)
Etapa 3: Configurando a propriedade OnClientClick para o botão Excluir em um CommandField
Ao trabalhar com um Botão, LinkButton ou ImageButton diretamente em um modelo, uma caixa de diálogo de confirmação pode ser associada a ele simplesmente configurando sua OnClientClick propriedade para retornar os resultados da função JavaScript confirm(string) . No entanto, o CommandField, que adiciona um campo de botões de exclusão a um GridView ou DetailsView, não possui uma propriedade OnClientClick que possa ser configurada declarativamente. Em vez disso, devemos programaticamente referenciar o botão Excluir no correspondente manipulador de eventos DataBound do GridView ou DetailsView e definir lá a sua propriedade OnClientClick.
Observação
Ao definir a propriedade do botão OnClientClick Excluir no manipulador de eventos DataBound apropriado, temos acesso aos dados vinculados ao registro atual. Isso significa que podemos estender a mensagem de confirmação para incluir detalhes sobre o registro específico, como: "Tem certeza de que deseja excluir o produto Chai?" Essa personalização também é possível em modelos usando a sintaxe de associação de dados.
Para praticar a configuração da propriedade OnClientClick dos botões Excluir em um CommandField, vamos adicionar um GridView à página. Configure este GridView para usar o mesmo controle ObjectDataSource usado pelo FormView. Limite também os BoundFields do GridView para incluir apenas o nome, a categoria e o fornecedor do produto. Por fim, marque a caixa de seleção "Habilitar Exclusão" na marca inteligente do GridView. Isso adicionará um CommandField à coleção GridView Columns com a sua propriedade ShowDeleteButton definida como true.
Depois de fazer essas alterações, a marcação declarativa do GridView deve ser semelhante à seguinte:
<asp:GridView ID="GridView1" runat="server" AutoGenerateColumns="False"
DataKeyNames="ProductID" DataSourceID="ObjectDataSource1">
<Columns>
<asp:CommandField ShowDeleteButton="True" />
<asp:BoundField DataField="ProductName" HeaderText="Product"
SortExpression="ProductName" />
<asp:BoundField DataField="CategoryName" HeaderText="Category" ReadOnly="True"
SortExpression="CategoryName" />
<asp:BoundField DataField="SupplierName" HeaderText="Supplier" ReadOnly="True"
SortExpression="SupplierName" />
</Columns>
</asp:GridView>
O CommandField contém uma única instância de Delete LinkButton que pode ser acessada programaticamente no manipulador de eventos do RowDataBound GridView. Uma vez referenciado, podemos definir sua OnClientClick propriedade adequadamente. Crie um manipulador de eventos para o RowDataBound evento usando o seguinte código:
Protected Sub GridView1_RowDataBound(ByVal sender As Object, _
ByVal e As System.Web.UI.WebControls.GridViewRowEventArgs) _
Handles GridView1.RowDataBound
If e.Row.RowType = DataControlRowType.DataRow Then
' reference the Delete LinkButton
Dim db As LinkButton = CType(e.Row.Cells(0).Controls(0), LinkButton)
' Get information about the product bound to the row
Dim product As Northwind.ProductsRow = _
CType(CType(e.Row.DataItem, System.Data.DataRowView).Row, _
Northwind.ProductsRow)
db.OnClientClick = String.Format( _
"return confirm('Are you certain you want to delete the {0} product?');", _
product.ProductName.Replace("'", "\'"))
End If
End Sub
Esse manipulador de eventos funciona com linhas de dados (aquelas que terão o botão Excluir) e começa referenciando programaticamente o botão Excluir. Em geral, use o seguinte padrão:
Dim obj As ButtonType = _
CType(e.Row.Cells(commandFieldIndex).Controls(controlIndex), ButtonType)
ButtonType é o tipo de botão que está sendo usado pelo CommandField – Button, LinkButton ou ImageButton. Por padrão, o CommandField usa LinkButtons, mas isso pode ser personalizado por meio do CommandField s ButtonType property. O commandFieldIndex é o índice ordinal do CommandField dentro da Columns coleção GridView, enquanto o controlIndex é o índice do botão Excluir dentro da Controls coleção CommandField. O valor controlIndex depende da posição do botão em relação a outros botões no CommandField. Por exemplo, se o único botão exibido no CommandField for o botão Excluir, use um índice de 0. Se, no entanto, houver um botão Editar que precede o botão Excluir, use um índice de 2. O motivo pelo qual um índice de 2 é usado é porque dois controles são adicionados pelo CommandField antes do botão Excluir: o botão Editar e um LiteralControl que é usado para adicionar algum espaço entre os botões Editar e Excluir.
Para nosso exemplo específico, o CommandField usa LinkButtons e, sendo o campo mais à esquerda, tem um commandFieldIndex de 0. Como não há outros botões além do botão Excluir no CommandField, usamos um controlIndex de 0.
Depois de referenciar o botão Excluir no CommandField, em seguida, obteremos informações sobre o produto associado à linha GridView atual. Por fim, definimos a propriedade do OnClientClick botão Excluir para o JavaScript apropriado, que inclui o nome do produto. Como a cadeia de caracteres JavaScript passada para a confirm(string) função é delimitada usando apóstrofos, devemos escapar de todos os apóstrofos que aparecem no nome do produto. Em particular, todos os apóstrofos no nome do produto são substituídos por "\'".
Com essas alterações concluídas, clicar em um botão Excluir no GridView exibe uma caixa de diálogo de confirmação personalizada (consulte a Figura 4). Assim como acontece com a caixa de mensagem de confirmação do FormView, se o usuário clicar em Cancelar o postback for cancelado, impedindo assim que a exclusão ocorra.
Observação
Essa técnica também pode ser usada para acessar programaticamente o botão Excluir no CommandField em um DetailsView. No entanto, para o DetailsView, você criaria um manipulador de eventos para o DataBound evento, já que o DetailsView não tem um RowDataBound evento.
Figura 4: Clicar no botão Excluir do GridView exibe uma caixa de diálogo de confirmação personalizada (clique para exibir a imagem em tamanho real)
Usando campos de modelo TemplateFields
Uma das desvantagens do CommandField é que seus botões devem ser acessados por meio da indexação e que o objeto resultante deve ser convertido no tipo de botão apropriado (Button, LinkButton ou ImageButton). O uso de "números mágicos" e tipos embutidos em código convida a problemas que não podem ser descobertos até o runtime. Por exemplo, se você ou outro desenvolvedor adicionar novos botões ao CommandField em algum momento no futuro (como um botão Editar) ou alterar a ButtonType propriedade, o código existente ainda será compilado sem erros, mas visitar a página pode causar uma exceção ou comportamento inesperado, dependendo de como o código foi escrito e quais alterações foram feitas.
Uma abordagem alternativa é converter os CommandFields de GridView e DetailsView em TemplateFields. Isso gerará um TemplateField com um ItemTemplate LinkButton (ou Button ou ImageButton) para cada botão no CommandField. Essas propriedades de botões podem ser atribuídas OnClientClick declarativamente, como vimos com o FormView ou podem ser acessadas programaticamente no manipulador de eventos apropriado DataBound usando o seguinte padrão:
Dim obj As ButtonType = CType(e.Row.FindControl("controlID"), ButtonType)
Onde controlID é o valor da propriedade do ID botão. Embora esse padrão ainda exija um tipo fixo no código para o elenco, ele remove a necessidade de indexação, permitindo que o layout seja alterado sem resultar em um erro de tempo de execução.
Resumo
A função JavaScript confirm(string) é uma técnica comumente usada para controlar o fluxo de trabalho de envio de formulário. Quando executada, a função exibe uma caixa de diálogo modal do lado do cliente que inclui dois botões, OK e Cancel. Se o usuário clicar em OK, a confirm(string) função retornará true; clicar em Cancelar retornará false. Essa funcionalidade, juntamente com o comportamento de um navegador para cancelar um envio de formulário se um manipulador de eventos durante o processo de envio retornar false, pode ser usada para exibir uma caixa de mensagem de confirmação ao excluir um registro.
A função confirm(string) pode ser associada ao manipulador de eventos no lado do cliente onclick do controle Button Web, por meio da propriedade OnClientClick do controle. Ao trabalhar com um botão Excluir em um modelo - em um dos modelos do FormView ou em um TemplateField no DetailsView ou GridView - essa propriedade pode ser definida de forma declarativa ou programática, como vimos neste tutorial.
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.