ASP .NET 4.0 - Usando o Web Control ClientIDMode


Em ASP.NET, cada controle web é identificado exclusivamente através da propriedade 'ID' do controle. Assim podemos acessar os controles de servidor no code-behind usando esta propriedade 'ID'. No entanto, quando o formulário web com os controles do lado do servidor é renderizado para HTML, o ID do lado do servidor é convertido em ID lado do cliente.

Ocorre que para os desenvolvedores do lado do cliente, torna-se difícil acessar os elementos HTML usando JavaScript pois a propriedade 'ID' é gerada em tempo de execução e não é conhecida em tempo de projeto. Embora você possa usar expressões para acessá-los, o código não fica muito legível.

Temos assim um problema com o qual o desenvolvedor tem que lidar e sobre o qual ele não tem muito o que fazer.

Felizmente na versão 4.0 da ASP .NET a Microsoft alterou esta situação e deu aos desenvolvedores o controle para processar o ID do lado do cliente para os controles de servidor, através da introdução de uma nova propriedade chamada 'ClientIDMode' .

A propriedade ClientIDMode obtém ou define um algoritmo usado para gerar o valor da propriedade ClientID para o controle. Em outras palavras, esta propriedade determina como o controle será renderizado.

Abaixo temos as opções de algoritmos usados para renderizar o ID do lado do servidor para o cliente:

AutoID O valor ClientID é gerado pela concatenação do ID pai dos valores de cada contêiner de nomeação com o valor do ID do controle. Em cenários de ligação de dados, onde várias instâncias de um controle são processadas, um valor de incremento é inserido na frente do valor ID do controle. Cada segmento é separado por um caractere de sublinhado (_). Esse algoritmo foi usado em versões do ASP.NET anteriores ao ASP.NET 4.
Static O valor do ClientID é definido como o valor da propriedade ID. Se o controle for um contêiner de nomeação, o controle é usado como o topo da hierarquia de recipientes de nomenclatura para todos os controles que ele contém.
Predictable È usado para controles de de dados vinculados. O o valor do ClientID é gerado pela concatenação do valor do ClientID do contêiner de nomeação pai com o valor do ID do controle. Se o controle é um controle dados vinculado que gera várias linhas, o valor do campo de dados especificado na propriedade ClientIDRowSuffix é adicionado no final.
Inherit O controle herda o ClientIDMode da configuração de seu controle pai. Nesta opção o ClientID será gerado da mesma forma que o ParentID. Ex: Se o ParentID é 'MainContent' então o TextBox 'txtNomeID' será nomeado como 'MainContent_txtNomeID'

Vamos agora mostrar alguns exemplos de como usar este recurso em aplicações ASP .NET usando o Visual Web Developer 2010 Express Edition.

Abra o Visual Web Developer 2010 Express Edition e no menu File clique em New Web Site;

A seguir selecione a linguagem Visual Basic e o template ASP .NET Web Site, informe o nome ASPNET_ClientID e clique em OK;

Vamos incluir 1 novo Web Form em nosso web site da seguinte forma:

No menu Web Site clique em Add New Item e selecione o template Web Form e informe o nome AutoID.aspx e selecione os itens: Place code in separate file e Select master page e clique em Add;

A seguir selecione a master page e clique no botão OK;

Vamos iniciar com o Web Form AutoID.aspx:

Selecione a página AutoID.aspx e no menu Table -> Insert Table inclua uma tabela com 6 Linhas e 2 colunas;

A seguir inclua os controles Label e TextBox conforme o leiaute abaixo:

Definição dos ID controles TextBox :
  • txtNome
  • txtEmail
  • txtCidade
  • txtPais

O código da página AutoID.aspx deve ser o seguinte:

<%@ Page Title="" Language="VB" MasterPageFile="~/Site.master" AutoEventWireup="false" 
CodeFile="AutoID.aspx.vb" Inherits="AutoID" %>
<asp:Content ID="Content1" ContentPlaceHolderID="HeadContent" Runat="Server">
    <style type="text/css">
        .style1{width: 100%;}
    </style>
</asp:Content>
<asp:Content ID="Content2" ContentPlaceHolderID="MainContent" Runat="Server">
    <script type="text/javascript" language="javascript">
    document.writeln('<% =txtNome.ClientID %>' + '<br>');
    document.writeln('<% =txtEmail.ClientID %>' + '<br>');
    document.writeln('<% =txtCidade.ClientID %>' + '<br>');
    document.writeln('<% =txtPais.ClientID %>' + '<br>');
    function getValor() {
        var txt_Email = document.getElementById('<% =txtEmail.ClientID %>');
        alert(txt_Email.value)
    }
</script>
    <table class="style1">
        <tr>
            <td>&nbsp;</td>
            <td>&nbsp;</td>
        </tr>
        <tr>
            <td bgcolor="#0099FF" colspan="2">&nbsp;</td>
        </tr>
        <tr>
            <td>Nome</td>
            <td><asp:TextBox ID="txtNome" runat="server" ClientIDMode="AutoID" height="22px" width="253px"></asp:TextBox></td>
        </tr>
        <tr>
            <td>Email</td>
            <td><asp:TextBox ID="txtEmail" runat="server" ClientIDMode="Static" Width="253px"></asp:TextBox></td>
        </tr>
        <tr>
            <td>Cidade</td>
            <td><asp:TextBox ID="txtCidade" runat="server" ClientIDMode="Inherit" height="22px" width="199px"></asp:TextBox></td>
        </tr>
        <tr>
            <td>Pais</td>
            <td><asp:TextBox ID="txtPais" runat="server" ClientIDMode="Static" Width="199px"></asp:TextBox></td>
        </tr>
        <tr>
            <td>&nbsp;</td>
            <td><asp:Button ID="btnEnviar" runat="server" Text="Enviar"  OnClientClick="getValor()" Width="111px" /></td>
        </tr>
        </table>
</asp:Content>

O código da página define o código para escrever no documento o nome dos controles:

document.writeln('<% =txtNome.ClientID %>' + '<br>');
document.writeln('<% =txtEmail.ClientID %>' + '<br>');
document.writeln('<% =txtCidade.ClientID %>' + '<br>');
document.writeln('<% =txtPais.ClientID %>' + '<br>');

A seguir definimos uma função JavaScript chamada getValor que irá obter o valor do controle txtEmail.ClientID e irá exibi-lo em uma caixa de alerta quando o botão Submeter for clicado pelo usuário:

function getValor() {
      var txt_Email = document.getElementById('<% =txtEmail.ClientID %>');
alert(txt_Email.value)
}

Observe que em cada definição de controle TextBox definimos a propriedade ClienteIDMode da seguinte forma:

Ao executar esta página e clicar no botão Submeter iremos obter o seguinte resultado:

Vemos a exibição dos nomes dos controles após sua renderização para o cliente notando a diferença nos nomes quando a propriedade é definida como AutoID e Static e Inherit;

Ao clicar no botão Submeter a função getValor() obtém o valor do controle txtEmail usando o código javascript: document.getElementById('<% =txtEmail.ClientID %>');

O ClientIDMode Predictable é útil quando usamos os controles de dados vinculados que renderiza mais do que um controle com o mesmo ID. Nestes casos usando Predictable podemos prever o id que o controle irá gerar quando renderizados do lado do cliente.

Vejamos um exemplo com o controle ListView onde usamos um XmlDataSource para definir os dados.

Vamos definir na página Default.aspx o seguinte leiaute e código:

O código fonte definido no modo Design pode ser visto abaixo:

<%@ Page Title="Home Page" Language="VB" MasterPageFile="~/Site.Master" AutoEventWireup="false"
    CodeFile="Default.aspx.vb" Inherits="_Default" %>

<asp:Content ID="HeaderContent" runat="server" ContentPlaceHolderID="HeadContent">
</asp:Content>
<asp:Content ID="BodyContent" runat="server" ContentPlaceHolderID="MainContent">
    <p>
        <asp:XmlDataSource ID="xdsTimes" runat="server">
        <Data>
            <Times>
                <time id="1" nome="São Paulo" />
                <time id="2" nome="Vasco" />
                <time id="3" nome="Botafogo" />
                <time id="4" nome="Corinthians" />
            </Times>
        </Data>
    </asp:XmlDataSource>
  </p>
  <asp:ListView runat="server" ID="lvMostraNomes" DataSourceID="xdsTimes"  ClientIDMode="Predictable" 
        style="color: #0033CC; font-size: large; font-weight: 700">
            <ItemTemplate>
                <asp:Label runat="server" Text='<%# Eval("nome") %>' ID="lblTimeNome"/> 
                <br> </br>
            </ItemTemplate>
        </asp:ListView>
</asp:Content>

Como eu defini o ClientIDmode como Predictable , o span que será renderizado no lado do cliente será assim:

<span id="MainContent_lvMostraNomes_lblTimeNome_0">São Paulo</span>
<span id="MainContent_lvMostraNomes_lblTimeNome_1">Vasco</span>
<span id="MainContent_lvMostraNomes_lblTimeNome_2">Botafogo</span>
<span id="MainContent_lvMostraNomes_lblTimeNome_3">Corinthians</span>

Portanto, você pode ver os ids serão gerados. Ele possui 4 partes (cada uma separada utilizando sublinhados). :

  1. A primeira parte representa o Nome da ContentPage; Ex: MainContent
  2. A próxima mostra o ListViewId; Ex: lvMostraNomes
  3. Em seguida o Id do Controle; Ex: lblTimeNomes
  4. No final temos um número único para cada registro; Ex: 0, 1, 2, ...

Se você quiser renderizar o sufixo com o mesmo id de cada controle pode usar uma propriedade chamada ClientIDRowSuffix para cada controle vinculado que habilita a usar o próprio sufixo para cada controle.

Para o nosso exemplo basta alterar o código para o ListView conforme abaixo:

<asp:ListView runat="server" ID="lvMostraNomes" DataSourceID="xdsTimes" ClientIDRowSuffix="id"
        style="color: #0033CC; font-size: large; font-weight: 700">
            <ItemTemplate>
                <asp:Label runat="server" Text='<%# Eval("nome") %>' ID="lblTimeNome"/>
                <br> </br>
            </ItemTemplate>
        </asp:ListView>
</asp:Content>

Após executar o html renderizado deverá ter o seguinte aspecto:

<span id="MainContent_lvMostraNomes_lblTimeNome_1">São Paulo</span>
<span id="MainContent_lvMostraNomes_lblTimeNome_2">Vasco</span>
<span id="MainContent_lvMostraNomes_lblTimeNome_3">Botafogo</span>
<span id="MainContent_lvMostraNomes_lblTimeNome_4">Corinthians</span>

Assim, o sufixo será o mesmo que o ID de registro de cada time.

Se definirmos a propriedade ClientIDRowSuffix como : ClientIDRowSuffix="id,nome"

Teremos o seguinte resultado:

<span id="MainContent_lvMostraNomes_lblTimeNome_1_São Paulo">São Paulo</span>
<span id="MainContent_lvMostraNomes_lblTimeNome_2_Vasco">Vasco</span>
<span id="MainContent_lvMostraNomes_lblTimeNome_3_Botafogo">Botafogo</span>
<span id="MainContent_lvMostraNomes_lblTimeNome_4_Corinthians">Corinthians</span>

Com a inclusão da propriedade ClientIDMode o problema de tratamento do ID do controle do lado do cliente foi resolvido. Uma dor de cabeça a menos...

Pegue o projeto completo aqui: ASPNET_ClientID.zip

"Pensai nas coisas que são de cima, e não nas que são da terra." Colossenses 3:2

Referências:


José Carlos Macoratti