Partilhar via


Adicionando confirmação de Client-Side ao excluir (C#)

por Scott Mitchell

Descarregar PDF

Nas interfaces que criamos até agora, um usuário pode excluir dados acidentalmente clicando no botão Excluir quando pretendia clicar no botão Editar. Neste tutorial, adicionaremos uma caixa de diálogo de confirmação do lado do cliente que aparece quando o botão Excluir é clicado.

Introdução

Ao longo dos ú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 Delete que, quando clicado, causa um postback e invoca o método ObjectDataSource Delete() . Delete() O método então 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 o comando 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 nenhum tipo de confirmação quando o usuário clica no botão Excluir. Se um usuário clicar acidentalmente no botão Excluir quando pretendia clicar em Editar, o registro que 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 string como o texto dentro de uma caixa de diálogo modal que vem equipada com dois botões - OK e Cancel (veja a Figura 1). A confirm(string) função retorna um valor booleano dependendo do botão clicado (true, se o usuário clicar em OK e false se clicar em Cancelar).

O método JavaScript confirm(string) exibe uma caixa de mensagem Client-Side modal

Figura 1: O método JavaScript confirm(string) exibe uma caixa de mensagem Client-Side modal

Durante um envio de formulário, se um valor de false for retornado de um manipulador de eventos do lado do cliente, o envio do formulário será cancelado. Usando esse recurso, podemos fazer com que o manipulador de eventos do lado onclick do cliente do botão Excluir 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 continuará inalterado e o produto será excluído. Consulte Usando o método JavaScript para controlar o confirm() envio de formulários para obter mais informações sobre essa técnica.

Adicionar o script necessário do lado do cliente difere ligeiramente ao usar modelos, diferente do uso de um CommandField. 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 seus usuários estejam visitando navegadores que suportam JavaScript e que tenham o JavaScript habilitado. Se qualquer uma dessas suposições não for verdadeira para um utilizador específico, clicar no botão Excluir causará imediatamente um recarregamento (sem exibir uma caixa de mensagem de confirmação).

Etapa 1: Criando um FormView que oferece suporte à exclusão

Comece por adicionar um FormView à página ConfirmationOnDelete.aspx na pasta EditInsertDelete, vinculando-a a um novo ObjectDataSource que extrai as informações do produto por meio do método ProductsBLL da classe GetProducts(). Configure também o método ObjectDataSource para que o ProductsBLL método s DeleteProduct(productID) da classe seja mapeado para o método s 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 Ativar paginação na etiqueta inteligente do FormView.

Após essas etapas, a nova marcação declarativa de 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 simultaneidade otimista, reserve um momento para limpar a propriedade s OldValuesParameterFormatString de ObjectDataSource.

Como ele foi vinculado a um controle ObjectDataSource que suporta apenas exclusão, o FormView s ItemTemplate oferece apenas o botão Excluir, faltando os botões Novo e Atualizar. A marcação declarativa do FormView, no entanto, inclui um supérfluo EditItemTemplate e InsertItemTemplate, que pode ser removido. Reserve um momento para personalizar o ItemTemplate para que seja mostrado apenas um subconjunto dos campos de dados do produto. Eu configurei o meu para mostrar o nome do produto num <h3> título acima dos seus nomes de fornecedor e categoria (junto com o botão Eliminar).

<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 mudanças, temos uma página web totalmente funcional que permite que um usuário alterne entre 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 visualizado através de um navegador.

O FormView mostra informações sobre um único produto

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 apagamento no evento de clique (onclick) Client-Side

Com o FormView criado, a etapa final é configurar o botão Excluir de modo que, quando clicado pelo visitante, a função JavaScript confirm(string) é invocada. A adição de script do lado do cliente a um evento do lado onclick do cliente de Button, LinkButton ou ImageButton pode ser realizada por meio do uso do OnClientClick property, que é novo no ASP.NET 2.0. Como queremos que o valor da função seja retornado confirm(string) , basta definir esta propriedade para: return confirm('Are you certain that you want to delete this product?');

Após essa alteração, a sintaxe declarativa de Delete LinkButton deve ser algo como:

<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 s ObjectDataSource Delete() será invocado, culminando com a exclusão do registro do 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). Em JavaScript, as cadeias de caracteres podem ser delimitadas usando qualquer caractere. Usamos apóstrofos aqui para que os delimitadores da cadeia de caracteres passada para confirm(string) não criem ambiguidade com os delimitadores usados para o valor da propriedade OnClientClick.

Uma confirmação agora é exibida ao clicar no botão Excluir

Figura 3: Uma confirmação agora é exibida ao clicar no botão Excluir (Clique para visualizar a imagem em tamanho real)

Etapa 3: Configuração da propriedade OnClientClick para o botão Excluir num elemento de comando

Ao trabalhar com um Button, 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 Delete a um GridView ou DetailsView - não tem uma OnClientClick propriedade que pode ser definida declarativamente. Em vez disso, devemos referenciar programaticamente o botão Eliminar no manipulador de eventos apropriado DataBound de GridView ou DetailsView, e, em seguida, definir a sua propriedade OnClientClick lá.

Observação

Ao definir a propriedade do botão Eliminar OnClientClick no manipulador de eventos apropriado DataBound, temos acesso aos dados associados ao registo 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 que usam sintaxe de vinculação de dados.

Para praticar a configuração da propriedade OnClientClick para o(s) botão(ões) Delete num CommandField, vamos adicionar um GridView à página. Configure este GridView para usar o mesmo controle ObjectDataSource que o FormView usa. Também limite os BoundFields do GridView para incluir apenas o nome, a categoria e o fornecedor do produto. Por fim, selecione a caixa de seleção Permitir eliminação na smart tag do GridView. Isso adicionará um CommandField à coleção de Columns do GridView, com a propriedade ShowDeleteButton definida como true.

Depois de fazer essas alterações, a marcação declarativa do GridView deve ter a seguinte aparência:

<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 ocorrência de Delete LinkButton que pode ser acessada programaticamente a partir do manipulador de eventos GridView RowDataBound . Uma vez referenciado, podemos definir a sua propriedade OnClientClick de acordo. Crie um manipulador de eventos para o RowDataBound evento usando o seguinte código:

protected void GridView1_RowDataBound(object sender, GridViewRowEventArgs e)
{
    if (e.Row.RowType == DataControlRowType.DataRow)
    {
        // reference the Delete LinkButton
        LinkButton db = (LinkButton)e.Row.Cells[0].Controls[0];

        // Get information about the product bound to the row
        Northwind.ProductsRow product =
            (Northwind.ProductsRow) ((System.Data.DataRowView) e.Row.DataItem).Row;

        db.OnClientClick = string.Format(
            "return confirm('Are you certain you want to delete the {0} product?');",
            product.ProductName.Replace("'", @"\'"));
    }
}

Este manipulador de eventos trabalha 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:

ButtonType obj = (ButtonType) e.Row.Cells[commandFieldIndex].Controls[controlIndex];

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 coleção GridView Columns , enquanto o controlIndex é o índice do botão Delete dentro da coleção s Controls 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. A razão pela 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 particular, 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 Delete no CommandField, usamos um controlIndex de 0.

Depois de fazer referência ao botão Excluir no CommandField, em seguida, obtemos informações sobre o produto vinculado à linha GridView atual. Finalmente, definimos a propriedade Delete button s OnClientClick para o JavaScript apropriado, que inclui o nome do produto. Como a string JavaScript passada para a confirm(string) função é delimitada usando apóstrofos, devemos escapar de quaisquer apóstrofos que apareçam no nome do produto. Em especial, quaisquer apóstrofos na denominação do produto são eliminados com "\'".

Com essas alterações concluídas, clicar em um botão Delete no GridView exibe uma caixa de diálogo de confirmação personalizada (veja a Figura 4). Tal como acontece com a caixa de mensagem de confirmação do FormView, se o usuário clicar em Cancelar o postback será cancelado, impedindo assim que a exclusão ocorra.

Observação

Essa técnica também pode ser usada para acessar programaticamente o botão Delete no CommandField em um DetailsView. Para o DetailsView, no entanto, você deve criar um manipulador de eventos para o DataBound evento, uma vez que o DetailsView não tem um RowDataBound evento.

Clicar no botão Excluir do GridView exibe uma caixa de diálogo de confirmação personalizada

Figura 4: Clicar no botão Excluir de GridView exibe uma caixa de diálogo de confirmação personalizada (Clique para visualizar a imagem em tamanho real)

Usando Campos de Modelo

Uma das desvantagens do CommandField é que seus botões devem ser acessados por meio de indexação e que o objeto resultante deve ser convertido para o tipo de botão apropriado (Button, LinkButton ou ImageButton). Usar "números mágicos" e tipos codificados convida a problemas que não podem ser descobertos até o tempo de execução. 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 erro, mas visitar a página pode causar uma exceção ou um comportamento inesperado, dependendo de como seu código foi escrito e quais alterações foram feitas.

Uma abordagem alternativa é converter os CommandFields de GridView e DetailsView em TemplateFields. Isto irá gerar um TemplateField com um ItemTemplate que contém um LinkButton (ou Button ou ImageButton) para cada botão no CommandField. Essas propriedades de botões OnClientClick podem ser atribuídas declarativamente, como vimos com o FormView, ou podem ser acessadas programaticamente no manipulador de eventos apropriado DataBound usando o seguinte padrão:

ButtonType obj = (ButtonType) e.Row.FindControl("controlID");

Onde controlID é o valor da propriedade do botão ID . Embora esse padrão ainda exija um tipo codificado para a transmissão, ele elimina 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ários. Quando executada, a função exibe uma caixa de diálogo modal, do lado do cliente, que inclui dois botões, OK e Cancelar. Se o utilizador clicar em OK, a confirm(string) função retorna true; ao clicar em Cancelar, retorna 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 cliente onclick do controlo Web Button através da propriedade OnClientClick do controlo. Ao trabalhar com um botão Delete em um modelo - em um dos modelos de FormView ou em um TemplateField em DetailsView ou GridView - essa propriedade pode ser definida declarativa ou programaticamente, como vimos neste tutorial.

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.