ASP .NET - Desabilitando o botão de comando após o primeiro click do usuário


Pode parecer sem importância mas a possibilidade do usuário clicar mais de uma vez em um botão de comando e assim disparar a execução de um novo processo/evento pode trazer muitas dores de cabeça.

Eu mesmo enfrentei esse problema em uma aplicação web onde o cliente confirmava uma transação financeira clicando em um botão de comando que disparava a execução da transação.

Se o cliente clicasse rapidamente duas vezes no botão eram iniciados duas transações levando a uma duplicidade na execução da transação o que naturalmente gerava uma anotação de débito em duplicidade na conta do cliente que não ficava muito feliz com isso.

Neste artigo eu vou mostrar uma das possibilidades de contornar o problema em uma aplicação ASP .NET.

Mas como você resolveria esta situação ?

Desativar um botão para evitar que ele seja clicado mais de uma vez pode parecer fácil a primeira vista.

Talvez a primeira coisa que lhe venha à mente para desabilitar o botão de comando é adicionar o seguinte código no lado do servidor: button.Enabled = false

E porque não ?

Afinal o código desabilita o botão atribuindo o valor à sua propriedade Enabled. Certo ??

Errado !!!

Infelizmente isso não vai desativar o botão uma vez que o botão tem que dar um post back para o servidor para executar a instrução.

Portanto você não pode usar o código do lado do servidor.

E então como resolvemos isso ?

A solução (uma das possíveis) é simples, e eu vou mostrar 3 variações da mesma solução que usa o evento OnClientClick do lado do cliente.

Resolvendo o problema

Como exemplo vou criar um projeto usando o Visual Web Developer 2010 Express Edition selecionando o menu New Project e escolhendo o template ASP .NET Empty Web Application com o nome: DesabilitarBotao

Agora vamos incluir 3 formulários web no projeto para apresentar as nossas soluções.

No menu Project clique em Add New Item, selecione o template Web Form e aceite o nome padrão WebForm1.aspx;

Repita o procedimento acima e inclua mais dois formulários web : WebForm2.aspx e WebForm3.aspx.

1 - No formulário WebForm1.aspx inclua um controle Button (Button1) conforme mostra o código e leiaute a seguir:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="DesabilitarBotao.WebForm1" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
 <title></title>
    <style type="text/css">
        .style1
        {
            color: #0033CC;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <h1 class="style1">Macoratti .net </h1>
    <hr />
    <div>
        <asp:Button ID="Button1" runat="server" Text="Confirmar Pedido" 
            onclick="Button1_Click" Width="234px" Height="26px" />
    </div>
    </form>
</body>
</html>

No code-behind inclua no arquivo WebForm1.aspx.cs o seguinte código:

using System;

namespace DesabilitarBotao
{
    public partial class WebForm1 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            Button1.Attributes.Add("onclick", "document.body.style.cursor = 'wait'; this.value='Aguarde, Enviando...'; this.disabled = true; " + this.GetPostBackEventReference(Button1, string.Empty) + ";");
        }

        protected void Button1_Click(object sender, EventArgs e)
        {
          
 System.Threading.Thread.Sleep(5000);
        }
    }
}

Neste código estamos adicionando o código JavaScript para desabilitar o botão ao evento onclick anexando-o à coleção Attributes do controle Button e então chamando a referencia ao evento Post Back para o botão após desabilitá-lo.

A propriedade Attributes permite adicionar HTML aos elementos de uma página :

 Button1.Attributes.Add("onclick", "alert('Macoratti')");
 Button1.Style.Add("background-color", "red");
 body.Attributes["bgcolor"] = "lightblue";

Executando o projeto iremos obter:

2 - No formulário WebForm2.aspx inclua um controle Button (Button1) e uma caixa de texto(txtDataSubmit) conforme mostra o código e leiaute a seguir:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm2.aspx.cs" Inherits="DesabilitarBotao.WebForm2" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
<script language="javascript" type="text/javascript">
       // desabilita o botao 
      function disableButtonOnClick(oButton, sButtonText) {
          oButton.disabled = true;
          // altera o texto do botão
          oButton.value = sButtonText;
      }
</script>
    <style type="text/css">
        .style1
        {
            color: #0033CC;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <h1 class="style1">Macoratti .net </h1>
    <hr />
    <div>
         Data de envio : <asp:TextBox ID="txtDataSubmit" runat="server"></asp:TextBox>
         <asp:Button ID="btnSubmit" runat="server" Text="Enviar Dados" onclick="btnSubmit_Click" />
        <br />
    </div>
    </form>
</body>
</htm>
 
 

Neste código definimos uma função JavaScript chamada disableButtonOnclick para desabilitar o botão.

No code-behind inclua no arquivo WebForm2.aspx.cs o seguinte código:

using System;
using System.Web.UI;

namespace DesabilitarBotao
{
    public partial class WebForm2 : System.Web.UI.Page
    {
        protected void Page_Load(object sender, EventArgs e)
        {
            PostBackOptions optionsSubmit = new PostBackOptions(btnSubmit);
            btnSubmit.OnClientClick = "disableButtonOnClick(this, 'Aguarde...'); ";
            btnSubmit.OnClientClick += ClientScript.GetPostBackEventReference(optionsSubmit);
        }

        protected void btnSubmit_Click(object sender, EventArgs e)
        {
            // simula a carga no servidor por 2 segundos
            System.Threading.Thread.Sleep(2000);
            // define a data no textbox
            txtDateSubmit.Text = DateTime.Now.ToString();
        }
    }
}

A ASP.NET apresenta a classe ClientScriptManager que contém métodos que podem ser usados para incluir código JavaScript no cliente. Os métodos da classe Page são também disponibilizados por esta nova classe e apresenta uma nova propriedade ClientScript que permite usar a nova classe, ou seja , podemos acessar a classe ClientScriptManager através de Page.ClientScript.

O método ClientScript.GetPostBackEventReference devolve uma cadeia que pode ser usada em um evento do cliente para causar um postback para o servidor. A seqüência de referência é definido pelo controle especificado que manipula o postback e um argumento de seqüência de informações de eventos adicionais.

Executando o projeto iremos obter:

 
   

3 - No formulário WebForm3.aspx inclua um controle Button (Button1) conforme mostra o código e leiaute a seguir:

<%@ Page Language="C#" AutoEventWireup="true" CodeBehind="WebForm3.aspx.cs" Inherits="DesabilitarBotao.WebForm3" %>

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">

<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
    <title></title>
    <style type="text/css">
        .style1
        {
            color: #0033CC;
        }
    </style>
</head>
<body>
    <form id="form1" runat="server">
    <h1 class="style1">Macoratti .net </h1>
    <hr />
    <div>
    <asp:Button runat="server" ID="BtnSubmit" OnClientClick="this.disabled = true; this.value = 'Enviando...';" UseSubmitBehavior="false" 
OnClick="BtnSubmit_Click" Text="Clique aqui para enviar!" />
    </div>
    </form>
</body>
</html>
 
 

Neste código definimos o código JavaScript no evento OnClientClick e definimos a propriedade Button.UseSubmitBehavior como false.

a propriedade Button.UseSubmitBehavior obtém ou define um valor indicando se o controle Button usa o mecanismo de envio do navegador do cliente(true) ou o mecanismo postback da ASP.NET (false). O valor padrão é true.

No code-behind inclua no arquivo WebForm3.aspx.cs o seguinte código:

using System;

namespace DesabilitarBotao
{
    public partial class WebForm3 : System.Web.UI.Page
    {
        protected void BtnSubmit_Click(object sender, EventArgs e)
        {
            System.Threading.Thread.Sleep(4000);
        }
    }
}

Executando o projeto teremos o seguinte resultado:

As 3 soluções apresentam o mesmo resultado. Escolha a mais adequada ou defina uma solução melhor.

Pegue o projeto completo aqui: DesabilitarBotao.zip

1Ts 5:4 Mas vós, irmãos, não estais em trevas, para que aquele dia, como ladrão, vos surpreenda;

1Ts 5:5 porque todos vós sois filhos da luz e filhos do dia; nós não somos da noite nem das trevas;

1Ts 5:6 não durmamos, pois, como os demais, antes vigiemos e sejamos sóbrios.

Referências:


José Carlos Macoratti