8. Componentes do servidor ASP - 2
8.1. Introduction
Continuamos nosso trabalho na interface do usuário, explorando:
- componentes de validação de dados
- como vincular dados a componentes de servidor
- os componentes de servidor HTML
8.2. Os componentes de validação de dados
8.2.1. Introdução
Em aplicativos com formulários, é fundamental verificar a validade dos dados inseridos neles. No exemplo sobre o cálculo de impostos, tínhamos o seguinte formulário:

Ao receber os valores desse formulário, precisamos verificar a validade dos dados inseridos: o número de filhos e o salário devem ser números inteiros positivos ou zero. Caso contrário, o formulário é reenviado ao cliente exatamente como foi preenchido, acompanhado de mensagens indicando os erros. Tratamos esse caso com duas visualizações, uma para o formulário acima e outra para os erros:

O ASP.NET oferece componentes chamados “componentes de validação”, que permitem verificar os seguintes casos:
Componente | Função |
verifica se um campo não está vazio | |
compara dois valores entre si | |
verifica se um valor está entre dois limites | |
verifica se um campo atende a uma expressão regular | |
permite que o desenvolvedor defina suas próprias regras de validação — esse componente poderia substituir todos os outros | |
permite reunir as mensagens de erro geradas pelos controles anteriores em um único local da página |
Apresentaremos agora cada um desses componentes.
8.2.2. RequiredFieldValidator
Estamos criando a seguinte página [requiredfieldvalidator1.aspx]:
![]() |
n.º | nome | tipo | propriedades | função |
1 | TextBox | EnableViewState=true | campo de entrada | |
2 | RequiredFieldValidator | EnableViewState=false EnableClientScript=true ErrorMessage=O campo [nome] é obrigatório | componente de validação | |
3 | Botão | EnableViewState=false CausesValidation=true | botão [submit] |
O campo [RequiredFieldValidator1] serve para exibir uma mensagem de erro caso o campo [txtNom] esteja vazio ou contenha uma sequência de espaços. Suas propriedades são as seguintes:
campo cujo valor deve ser verificado pelo componente. O que significa o valor de um componente? É o valor do atributo [value] da tag HTML correspondente. Para um [TextBox], será o conteúdo do campo de entrada; para um [DropDownList], será o valor do elemento selecionado. | |
booleano — se for verdadeiro, indica que o conteúdo do campo anterior também deve ser verificado no lado do cliente. Nesse caso, o formulário só será enviado pelo navegador se não houver erros. No entanto, as verificações de validação também são realizadas no servidor, para o caso de o cliente não ser um navegador, por exemplo. | |
a mensagem de erro que o componente deve exibir caso seja detectado um erro |
A verificação dos dados da página pelos controles de validação só é realizada se o botão ou o link que acionou o [POST] da página possuir a propriedade [CausesValidation=true]. [true] é o valor padrão dessa propriedade.
Vamos executar esta aplicação. Primeiro, usaremos um navegador [Mozilla]:

O código HTML recebido por [Mozilla] é o seguinte:
<html>
<head>
</head>
<body>
<form name="_ctl0" method="post" action="requiredfieldvalidator1.aspx" id="_ctl0">
<input type="hidden" name="__VIEWSTATE" value="dDwxNDI1MDc1NTU1Ozs+SGtdZvVxefDCDxnsqbDnqCaROsk=" />
<p>
Demande du dossier de candidature au DESS
</p>
<fieldset>
<legend>[--Identité--]</legend>
<table>
<tbody>
<tr>
<td>
Nom*</td>
<td>
<input name="txtNom" type="text" id="txtNom" />
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<input type="submit" name="btnEnvoyer" value="Envoyer" onclick="if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(); " language="javascript" id="btnEnvoyer" />
</p>
</form>
</body>
</html>
Percebe-se que o botão [btnEnvoyer] está vinculado a uma função JavaScript por meio de seu atributo [onclick]. Observa-se também que a página não contém nenhum código [Javascript]. O teste [typeof(Page_ClientValidate) == 'function'] falhará e a função JavaScript não será chamada. O formulário será então enviado ao servidor, e caberá a ele realizar as verificações de validade. Vamos usar o botão [Envoyer] sem definir um nome. A resposta do servidor é a seguinte:

O que aconteceu? O formulário foi enviado ao servidor. Este executou o código de todos os componentes de validação presentes na página. Aqui, há apenas um. Se pelo menos um componente de validação detectar um erro, o servidor retorna o formulário exatamente como foi preenchido (na verdade, para os componentes com [EnableViewState=true], além de uma mensagem de erro para cada componente de validação que detectou um erro). Essa mensagem é o atributo [ErrorMessage] do componente de validação. É esse mecanismo que vemos em ação acima. Se inserirmos algo no campo [nom], a mensagem de erro não aparecerá mais ao validar o formulário:

Agora, vamos usar o Internet Explorer e acessar a URL [http://localhost/requiredfieldvalidator1.aspx]. Obtemos a seguinte página:

O código HTML recebido por IE é o seguinte:
<html>
<head>
</head>
<body>
<form name="_ctl0" method="post" action="requiredfieldvalidator1.aspx" language="javascript" onsubmit="ValidatorOnSubmit();" id="_ctl0">
<input type="hidden" name="__VIEWSTATE" value="dDwxNDI1MDc1NTU1Ozs+SGtdZvVxefDCDxnsqbDnqCaROsk=" />
<script language="javascript" src="/aspnet_client/system_web/1_1_4322/WebUIValidation.js"></script>
<p>
Demande du dossier de candidature au DESS
</p>
<fieldset>
<legend>[--Identité--]</legend>
<table>
<tbody>
<tr>
<td>
Nom*</td>
<td>
<input name="txtNom" type="text" id="txtNom" />
<span id="RequiredFieldValidator1" controltovalidate="txtNom" errormessage="Le champ [nom] est obligatoire" evaluationfunction="RequiredFieldValidatorEvaluateIsValid" initialvalue="" style="color:Red;visibility:hidden;">Le champ [nom] est obligatoire</span>
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<input type="submit" name="btnEnvoyer" value="Envoyer" onclick="if (typeof(Page_ClientValidate) == 'function') Page_ClientValidate(); " language="javascript" id="btnEnvoyer" />
</p>
<script language="javascript">
<!--
var Page_Validators = new Array(document.all["RequiredFieldValidator1"]);
// -->
</script>
<script language="javascript">
<!--
var Page_ValidationActive = false;
if (typeof(clientInformation) != "undefined" && clientInformation.appName.indexOf("Explorer") != -1) {
if (typeof(Page_ValidationVer) == "undefined")
alert("Impossible de trouver la bibliothèque de scripts /aspnet_client/system_web/1_1_4322/WebUIValidation.js. Essayez de placer ce fichier manuellement ou effectuez une réinstallation en exécutant 'aspnet_regiis -c'.");
else if (Page_ValidationVer != "125")
alert("Cette page utilise une version incorrecte de WebUIValidation.js. La page requiert la version 125. La bibliothèque de scripts est " + Page_ValidationVer + ".");
else
ValidatorOnLoad();
}
function ValidatorOnSubmit() {
if (Page_ValidationActive) {
ValidatorCommonOnSubmit();
}
}
// -->
</script>
</form>
</body>
</html>
Percebe-se que esse código é muito mais extenso do que o recebido por [Mozilla]. Não entraremos em detalhes. A diferença decorre do fato de que o servidor incluiu funções JavaScript no documento HTML enviado. Por que existem dois códigos HTML diferentes, se a URL solicitada pelos dois navegadores é a mesma? Já mencionamos que a tecnologia ASP.NET fazia com que o servidor adaptasse o documento HTML enviado ao cliente de acordo com as características desse cliente. Existem no mercado diversos navegadores, nem todos com as mesmas capacidades. Os navegadores da Microsoft e da Netscape, por exemplo, não utilizam a mesma modelagem de objetos para o documento que recebem. Portanto, o código JavaScript para manipular esse documento no lado do navegador apresenta diferenças entre os dois navegadores. Da mesma forma, os desenvolvedores criaram versões sucessivas de seus navegadores, aprimorando constantemente suas capacidades. Portanto, um documento HTML compreendido pelo IE5 pode não ser compreendido pelo IE3. Temos acima um exemplo dessa adaptação do servidor em relação ao seu cliente. Por um motivo que não foi aprofundado aqui, o servidor web considerou que o cliente [Mozilla] não tinha capacidade para processar o código JavaScript de validação. Por isso, esse código não foi incluído no documento HTML que lhe foi enviado, e a validação foi realizada no lado do servidor. Para o [IE6], esse código JavaScript foi incluído no documento HTML enviado, como podemos ver. Para ver como isso funciona, vamos fazer o seguinte experimento:
- desliguemos o servidor web
- usemos o botão [Envoyer] sem preencher o campo [nom]
Obtemos a seguinte nova página:

Foi mesmo o navegador que exibiu a mensagem de erro. De fato, o servidor está desligado. Podemos confirmar isso inserindo algo no campo [nom] e clicando em “Validar”. Desta vez, a resposta é a seguinte:

O que aconteceu? O navegador executou o código JavaScript de validação. Esse código indicou que a página estava válida. O navegador, então, enviou o formulário para o servidor web, que estava desligado. O navegador percebeu isso e exibiu a página acima. Se reiniciarmos o servidor, tudo volta ao normal.
O que podemos aprender com esse exemplo?
- a importância do conceito de componente de validação, que permite reenviar ao cliente qualquer formulário incorreto
- a importância do [VIEWSTATE], que permite reenviar esse formulário exatamente como foi preenchido
- a capacidade de adaptação do servidor ao seu cliente. Este é identificado pelo cabeçalho HTTP [User-Agent:] que ele envia ao servidor. Portanto, não é o servidor que “adivinha” com quem está lidando. Essa capacidade de adaptação é de grande interesse para o desenvolvedor, que não precisa se preocupar com o tipo de cliente de seu aplicativo.
8.2.3. CompareValidator
Criamos a seguinte página [comparevalidator1.aspx]:

n.º | nome | tipo | propriedades | função |
1 | DropDownList | EnableViewState=true | lista suspensa | |
2 | DropDownList | EnableViewState=true | lista suspensa | |
3 | CompareValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Opção 1 inválida ValorParaComparar=? Operador=NãoIgual Tipo=string | componente de validação | |
4 | CompareValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Opção 2 inválida ControlToCompare=? Operador=Diferente Tipo=string | componente de validação | |
5 | Botão | EnableViewState=false CausesValidation=true | botão [submit] |
O componente [CompareValidator] serve para comparar dois valores entre si. Os operadores que podem ser utilizados são [Equal, NotEqual, LessThan, LessThanEqual, GreaterThan, GreaterThanEqual]. O primeiro valor é definido pela propriedade [ControlToValidate]; o segundo, por [ValueToCompare], caso o valor anterior deva ser comparado a uma constante, ou por [ControlToCompare], caso deva ser comparado ao valor de outro componente. As propriedades importantes do componente [CompareValidator] são as seguintes:
campo cujo conteúdo deve ser verificado pelo componente | |
booleano — quando verdadeiro, indica que o conteúdo do campo anterior também deve ser verificado no lado do cliente | |
a mensagem de erro que o componente deve exibir caso seja detectado um erro | |
valor com o qual o valor do campo deve ser comparado [ControlToValidate] | |
componente cujo valor deve ser comparado ao valor do campo [ControlToValidate] | |
operador de comparação entre os dois valores | |
tipo dos valores a serem comparados |
O código de apresentação desta página é o seguinte:
<html>
<head>
</head>
<body>
<form runat="server">
<p>
Demande du dossier de candidature au DESS
</p>
<fieldset>
<legend>[--Options du DESS pour lesquelles vous candidatez--]</legend>
<table>
<tbody>
<tr>
<td>
Option1*</td>
<td>
Option2</td>
</tr>
<tr>
<td>
<asp:DropDownList id="cmbChoix1" runat="server">
<asp:ListItem Value="?" Selected="True">?</asp:ListItem>
<asp:ListItem Value="Automatique">Automatique</asp:ListItem>
<asp:ListItem Value="Informatique">Informatique</asp:ListItem>
</asp:DropDownList>
</td>
<td>
<asp:DropDownList id="cmbChoix2" runat="server">
<asp:ListItem Value="?">?</asp:ListItem>
<asp:ListItem Value="Automatique">Automatique</asp:ListItem>
<asp:ListItem Value="Informatique">Informatique</asp:ListItem>
</asp:DropDownList>
</td>
</tr>
<tr>
<td>
<asp:CompareValidator id="CompareValidator1" runat="server" ErrorMessage="Choix 1 invalide" ControlToValidate="cmbChoix1" ValueToCompare="?" Operator="NotEqual"></asp:CompareValidator>
</td>
<td>
<asp:CompareValidator id="CompareValidator2" runat="server" ErrorMessage="Choix 2 invalide" ControlToValidate="cmbChoix2" Operator="NotEqual" ControlToCompare="cmbChoix1"></asp:CompareValidator>
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<asp:Button id="btnEnvoyer" runat="server" Text="Envoyer"></asp:Button>
</p>
</form>
</body>
</html>
As restrições de validação da página são as seguintes:
- o valor selecionado em [cmbChoix1] deve ser diferente da sequência de caracteres “?”. Isso implica as seguintes propriedades para o componente [CompareValidator1]: Operator=NotEqual, ValueToCompare=?, Type=string
- o valor selecionado em [cmbChoix2] deve ser diferente daquele selecionado em [cmbChoix1]. Isso implica as seguintes propriedades para o componente [CompareValidator2]: Operador=NotEqual, ControlToCompare=cmbChoix1, Tipo=string
Executamos essa aplicação. Aqui está um exemplo de página recebida durante as trocas cliente-servidor:

Se a mesma página for acessada pelo Internet Explorer 6, um código JavaScript é incluído nela, o que resulta em um funcionamento ligeiramente diferente. Eventuais erros são sinalizados assim que o usuário altera o valor em uma das listas suspensas. Trata-se de uma melhoria no conforto do usuário.
8.2.4. CustomValidator, RangeValidator
Estamos criando a seguinte página [customvalidator1.aspx]:

n.º | nome | tipo | propriedades | função |
DropDownList | EnableViewState=true | lista suspensa | ||
CompareValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Certificado inválido Operator=NotEqual ValueToCompare=? Tipo=String | componente de validação do controle [1] | ||
TextBox | EnableViewState=false | campo de entrada | ||
CustomValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Detalhes do diploma inválidos ClientValidationFunction=chkOutroDiploma | componente de validação do campo [3] | ||
TextBox | EnableViewState=false | campo de entrada | ||
RangeValidator | EnableViewState=false EnableClientScript=true ErrorMessage=O ano de formatura deve estar no intervalo [1990,2004] MinValue=1990 MaxValue=2004 Tipo=Inteiro ControlToValidate=txtAnDiplome | componente de validação do campo [5] | ||
RequiredFieldValidator | EnableViewState=false EnableClientScript=true ErrorMessage=É necessário informar o ano de formatura ControlToValidate=txtAnDiplome | componente de validação do campo [5] | ||
Botão | EnableViewState=false CausesValidation=true | botão [submit] |
O campo [RangeValidator] serve para verificar se o valor de um controle está entre os limites [MinValue] e [MaxValue]. Suas propriedades são as seguintes:
campo cujo valor deve ser verificado pelo componente | |
booleano — quando verdadeiro, indica que o conteúdo do campo anterior também deve ser verificado no lado do cliente | |
a mensagem de erro que o componente deve exibir caso seja detectado um erro | |
valor mínimo do campo a ser verificado | |
valor máximo do campo a ser verificado | |
tipo do valor do campo a ser verificado |
O campo [CustomValidator] permite realizar validações que não podem ser feitas pelos componentes de validação oferecidos pelo ASP.NET. Essa validação é realizada por uma função escrita pelo desenvolvedor. Ela é executada no lado do servidor. Como a verificação também pode ser feita no lado do cliente, o desenvolvedor pode precisar criar uma função JavaScript para incluir no documento HTML. Suas propriedades são as seguintes:
campo cujo valor deve ser verificado pelo componente | |
booleano — quando verdadeiro, indica que o conteúdo do campo anterior também deve ser verificado no lado do cliente | |
a mensagem de erro que o componente deve exibir caso seja detectado um erro | |
a função a ser executada no lado do cliente |
O código de apresentação da página é o seguinte:
<%@ Page Language="VB" %>
<script runat="server">
...
</script>
<html>
<head>
</head>
<body>
<form runat="server">
<p align="left">
Demande du dossier de candidature au DESS
</p>
<fieldset>
<legend>[--Votre dernier diplôme--]</legend>
<table>
<tbody>
<tr>
<td>
Diplôme*</td>
<td>
<asp:DropDownList id="cmbDiplomes" runat="server">
<asp:ListItem Value="?">?</asp:ListItem>
<asp:ListItem Value="[Autre]">[Autre]</asp:ListItem>
<asp:ListItem Value="Maîtrise">Maîtrise</asp:ListItem>
<asp:ListItem Value="DESS">DESS</asp:ListItem>
<asp:ListItem Value="DEA">DEA</asp:ListItem>
</asp:DropDownList>
</td>
<td>
Si [Autre], précisez</td>
<td>
<asp:TextBox id="txtAutreDiplome" runat="server" EnableViewState="False"></asp:TextBox>
</td>
</tr>
<tr>
<td>
</td>
<td>
<p>
<asp:CompareValidator id="CompareValidator2" runat="server" ErrorMessage="Diplôme invalide" ControlToValidate="cmbDiplomes" ValueToCompare="?" Operator="NotEqual" ></asp:CompareValidator>
</p>
</td>
<td>
</td>
<td>
<asp:CustomValidator id="CustomValidator1" runat="server" ErrorMessage="Précision diplôme invalide" OnServerValidate="CustomValidator1_ServerValidate_1" EnableViewState="False" ClientValidationFunction="chckAutreDiplome"></asp:CustomValidator>
</td>
</tr>
<tr>
<td>
Année d'obtention*</td>
<td colspan="3">
<asp:TextBox id="txtAnDiplome" runat="server" Columns="4"></asp:TextBox>
<asp:RangeValidator id="RangeValidator1" runat="server" ErrorMessage="Année diplôme doit être dans l'intervalle [1990,2004]" ControlToValidate="txtAnDiplome" MinimumValue="1990" MaximumValue="2004" Type="Integer"></asp:RangeValidator>
<asp:RequiredFieldValidator id="RequiredFieldValidator2" runat="server" ErrorMessage="Année diplôme requise" ControlToValidate="txtAnDiplome"></asp:RequiredFieldValidator>
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<asp:Button id="btnEnvoyer" runat="server" Text="Envoyer"></asp:Button>
</p>
</form>
</body>
</html>
O atributo [OnServerValidate] do componente [CustomValidator] permite especificar a função responsável pela validação no lado do servidor. Acima, o componente [CustomValidator1] chama o seguinte procedimento [CustomValidator1_ServerValidate_1]:
<%@ Page Language="VB" %>
<script runat="server">
Sub CustomValidator1_ServerValidate_1(sender As Object, e As ServerValidateEventArgs)
' o campo [txtAutreDiplome] deve ser preenchido se [cmbDiplomes]=[autre]
e.isvalid=not (cmbDiplomes.selecteditem.text="[Autre]" and txtAutreDiplome.text.trim="") _
and not (cmbDiplomes.selecteditem.text<>"[Autre]" and cmbDiplomes.selecteditem.text<>"?" and txtAutreDiplome.text.trim<>"")
End Sub
</script>
....
Uma função de validação associada a um componente [CustomValidator] recebe dois parâmetros:
- sender: objeto que provocou o evento
- e: o evento. O procedimento deve definir o atributo [e.IsValid] como verdadeiro se os dados verificados estiverem corretos e como falso caso contrário.
Aqui, as verificações realizadas são as seguintes:
- a lista suspensa [cmbDiplomes] não pode ter o valor [?]. Isso é verificado pelo componente [CompareValidator2]
- o usuário seleciona um diploma na lista suspensa [cmbDiplomes]. Se o diploma não estiver na lista, ele pode selecionar a opção [Autre] da lista. Ele deve, então, indicar seu diploma no campo de entrada [txtAutreDiplome]. Se [Autre] for selecionado em [cmbDiplomes], o campo [txtAutreDiplome] deve conter um valor. Se nem [Autre] nem [?] forem selecionados em [cmbDiplomes], o campo [txtAutreDiplome] deve estar vazio. Isso é verificado pela função associada ao componente [CustomValidator1].
- O ano de obtenção do diploma deve estar no intervalo [1900-2004]. Isso é verificado por [RangeValidator1]. No entanto, se o usuário não inserir nada no campo, a função de validação de [RangeValidator1] não é utilizada. Por isso, adiciona-se o componente [RequiredFieldValidator2] para verificar a presença de conteúdo. Essa é uma regra geral. O conteúdo de um campo não é verificado se ele estiver vazio. O único caso em que isso ocorre é quando ele está associado a um componente [RequiredFieldValidator].
Aqui está um exemplo de execução no navegador [Mozilla]:

Se utilizarmos o navegador [IE6], podemos adicionar uma função de validação do lado do cliente para o componente [CustomValidator1]. Para isso, esse componente possui as seguintes propriedades:
- EnableClientScript=true
- ClientValidationFunction=chkOutroDiploma
A função [chkAutreDiplome ] é a seguinte:
<head>
<meta http-equiv="pragma" content="no-cache" />
<script language="javascript">
function chkAutreDiplome(source,args){
// verifica a validade do campo txtAutreDiplome
with(document.frmCandidature){
diplome=cmbDiplomes.options[cmbDiplomes.selectedIndex].text;
args.IsValid= !(diplome=="[Autre]" && txtAutreDiplome.value=="")
&& ! (diplome!="[Autre]" && diplome!="?" && txtAutreDiplome.value!="");
}
}
</script>
</head>
A função [chkAutreDiplome] recebe os mesmos dois parâmetros que a função de servidor [CustomValidator1_ServerValidate_1]:
- fonte: o objeto que provocou o evento
- args: o evento. Este possui um atributo [IsValid] que deve ser definido como verdadeiro pela função caso os dados verificados estejam corretos. Um valor falso exibirá, no local do componente de validação, a mensagem de erro associada a ele, e o formulário não será enviado ao servidor.
8.2.5. RegularExpressionValidator
Criamos a seguinte página [regularexpressionvalidator1.aspx]:

n.º | nome | tipo | propriedades | função |
TextBox | EnableViewState=true | campo de entrada | ||
RequiredFieldValidator | ControlToValidate=txtMel Display=Dynamic | componente de validação do controle [1] | ||
RegularExpressionValidator | ControlToValidate=txtMel Display=Dynamic | componente de validação do controle [1] | ||
Botão | EnableViewState=false CausesValidation=true | botão [submit] |
Aqui, queremos verificar o formato de um endereço de e-mail. Fazemos isso com um componente [RegularExpressionValidator], que permite verificar a validade de um campo por meio de uma expressão regular. Vale lembrar que uma expressão regular é um padrão de sequência de caracteres. Portanto, verificamos o conteúdo de um campo em relação a esse padrão. Como o conteúdo de um campo não é verificado se estiver vazio, precisamos também de um componente [RequiredFieldValidator] para verificar se o endereço de e-mail não está vazio. A classe [RegularExpressionValidator] possui propriedades semelhantes às das classes dos componentes já estudados:
campo cujo valor deve ser verificado pelo componente | |
booleano — quando verdadeiro, indica que o conteúdo do campo anterior também deve ser verificado no lado do cliente | |
a mensagem de erro que o componente deve exibir caso seja detectado um erro | |
a expressão regular com a qual o conteúdo de [ControlToValidate] será comparado | |
modo de exibição: Static: o campo está sempre presente, mesmo que não exiba nenhuma mensagem de erro; Dynamic: o campo só está presente se houver uma mensagem de erro; None: a mensagem de erro não é exibida. Esse campo também existe para os outros componentes, mas não havia sido utilizado até agora. |
A expressão regular modelo de um endereço de e-mail poderia ser a seguinte: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*
Um endereço de e-mail tem o formato [champ1.champ2....@champA.champB...]. É obrigatório que haja pelo menos um campo antes do símbolo @ e pelo menos dois campos depois dele. Esses campos são compostos por caracteres alfanuméricos e pelo símbolo -. O caractere alfanumérico é representado pelo símbolo \w. A sequência [\w-] significa o caractere \w ou o caractere -. O sinal + após uma sequência S significa que ela pode se repetir uma ou mais vezes; o sinal * significa que ela pode se repetir zero ou mais vezes; o sinal ? significa que ela pode se repetir zero ou uma vez.
Um campo do endereço de e-mail corresponde ao modelo [\w-]+. O fato de haver obrigatoriamente pelo menos um campo antes do sinal @ e pelo menos dois depois, separados pelo sinal ., corresponde ao modelo: [\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+. É possível permitir que o usuário insira espaços antes e depois do endereço. Eles serão removidos durante o processamento. Uma sequência de espaços, eventualmente vazia, é representada pelo padrão \s*. Daí a expressão regular do endereço de e-mail: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*.
O código de apresentação da página é, então, o seguinte:
<html>
<head>
</head>
<body>
<form runat="server">
<p align="left">
Demande du dossier de candidature au DESS
</p>
<fieldset>
<legend>[--Votre adresse électronique où sera envoyé le dossier de candidature--]</legend>
<table>
<tbody>
<tr>
<td>
<asp:TextBox id="txtMel" runat="server" Columns="60"></asp:TextBox>
</td>
</tr>
<tr>
<td>
<p>
<asp:RequiredFieldValidator id="RequiredFieldValidator3" runat="server" Display="Dynamic" ControlToValidate="txtMel" ErrorMessage="Votre adresse électronique est requise"></asp:RequiredFieldValidator>
</p>
<p>
<asp:RegularExpressionValidator id="RegularExpressionValidator1" runat="server" Display="Dynamic" ControlToValidate="txtMel" ErrorMessage="Votre adresse électronique n'a pas un format valide" ValidationExpression="\s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*"></asp:RegularExpressionValidator>
</p>
</td>
</tr>
</tbody>
</table>
</fieldset>
<p>
<asp:Button id="btnEnvoyer" runat="server" Text="Envoyer"></asp:Button>
</p>
</form>
</body>
</html>
8.2.6. ValidationSummary
Por motivos estéticos, pode-se querer reunir as mensagens de erro em um único local, como no exemplo a seguir: [summaryvalidator1.aspx], onde reunimos em uma única página todos os exemplos anteriores:

Todos os controles de validação possuem as seguintes propriedades:
- [Display=Dynamic], o que faz com que os controles não ocupem espaço na página se sua mensagem de erro estiver vazia
- [EnableClientScript=false] para impedir qualquer validação no lado do cliente
- [Text=*]. Essa será a mensagem exibida em caso de erro, sendo que o conteúdo do atributo [ErrorMessage] é exibido pelo controle [ValidationSummary], que apresentamos a seguir.
Esse conjunto de controles está inserido em um componente [Panel] denominado [vueFormulaire]. Em outro componente [Panel], denominado [vueErreurs], colocamos um controle [ValidationSummary]:

n.º | nome | tipo | propriedades | função |
1 | ValidationSummary | HeaderText=Ocorreram os seguintes erros, EnableClientScript=false, ShowSummary=true | exibe os erros de todos os controles de validação da página | |
2 | LinkButton | CausesValidation=false | link de retorno ao formulário |
Para o link [lnkErreursToFormulaire], não é necessário ativar a validação, pois esse link não envia nenhum valor a ser verificado.
Quando todos os dados estão válidos, é exibida ao usuário a seguinte visualização [infos]:

1
n.º | nome | tipo | propriedades | função |
1 | Rótulo | mensagem informativa destinada ao usuário |
O código de apresentação desta página é o seguinte:
<html>
<head>
</head>
<body>
<form runat="server">
<p align="left">
Demande du dossier de candidature au DESS
</p>
<p>
<hr />
<asp:panel id="vueErreurs" runat="server">
<p align="left">
<asp:ValidationSummary id="ValidationSummary1" runat="server" ShowMessageBox="True" BorderColor="#C04000" BorderWidth="1px" BackColor="#FFFFC0" HeaderText="Les erreurs suivantes se sont produites"></asp:ValidationSummary>
</p>
<p>
<asp:LinkButton id="lnkErreursToFormulaire" onclick="lnkErreursToFormulaire_Click" runat="server" CausesValidation="False">Retour au formulaire</asp:LinkButton>
</p>
</asp:panel>
<asp:panel id="vueFormulaire" runat="server">
....
<asp:Button id="btnEnvoyer" onclick="btnEnvoyer_Click" runat="server" Text="Envoyer"></asp:Button>
</p>
</asp:panel>
<asp:panel id="vueInfos" runat="server">
<asp:Label id="lblInfo" runat="server"></asp:Label>
</asp:panel>
</form>
</body>
</html>
Aqui estão alguns exemplos de resultados obtidos. Validamos a visualização [formulaire] sem inserir valores:

O botão [Envoyer] nos fornece a seguinte resposta:

A visualização [erreurs] foi exibida. Se usarmos o link de retorno ao formulário, o encontraremos no seguinte estado:

Trata-se da visualização [formulaire]. Observe o caractere [*] próximo aos dados incorretos. Trata-se do campo [Text] dos controles de validação que foi exibido. Se preenchermos os campos corretamente, obteremos a visualização [infos]:

O código de controle da página é o seguinte:
<%@ Page Language="VB" %>
<script runat="server">
' procedimento executado ao carregar a página
Sub page_Load(sender As Object, e As EventArgs)
' na primeira solicitação, é exibida a visualização [formulaire]
if not ispostback then
afficheVues(true,false,false)
end if
end sub
sub afficheVues(byval formulaireVisible as boolean, _
erreursVisible as boolean, infosVisible as boolean)
' conjunto de visualizações
vueFormulaire.visible=formulaireVisible
vueErreurs.visible=erreursVisible
vueInfos.visible=infosVisible
end sub
Sub CustomValidator1_ServerValidate(sender As Object, e As ServerValidateEventArgs)
...
End Sub
Sub CustomValidator2_ServerValidate(sender As Object, e As ServerValidateEventArgs)
...
End Sub
Sub CustomValidator1_ServerValidate_1(sender As Object, e As ServerValidateEventArgs)
...
End Sub
Sub lnkErreursToFormulaire_Click(sender As Object, e As EventArgs)
' exibe a visualização do formulário
afficheVues(true,false,false)
' repete as verificações de validade
Page.validate
End Sub
Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
' a página está válida?
if not Page.IsValid then
' exibe-se a visualização [erreurs]
afficheVues(false,true,false)
else
' caso contrário, a visualização [infos]
lblInfo.Text="Le dossier de candidature au DESS IAIE a été envoyé à l'adresse ["+ _
txtMel.Text + "]. Nous vous en souhaitons bonne réception.<br><br>Le secrétariat du DESS."
afficheVues(false,false,true)
end if
end sub
</script>
<html>
...
</html>
- No procedimento [Page_Load], executado a cada solicitação do cliente, exibimos a visualização [formulaire], ficando as demais ocultas. Isso ocorre apenas na primeira solicitação. O procedimento chama um procedimento utilitário [afficheVues], ao qual são passados três valores booleanos para determinar se as três visualizações devem ou não ser exibidas.
- Quando o procedimento [btnEnvoyer_Click] é chamado, as verificações de dados já foram realizadas. O botão [btnEnvoyer] possui a propriedade [CausesValidation=true], que força essa verificação de dados. Todas as verificações de validação foram executadas e sua propriedade [IsValid] foi definida. Essa propriedade indica se o dado verificado pelo controle era válido ou não. Além disso, a propriedade [IsValid] da própria página também foi definida. Ela assume o valor [vrai] apenas se a propriedade [IsValid] de todos os controles de validação da página tiver o valor [vrai]. Assim, o procedimento [btnEnvoyer_Click] começa verificando se a página é válida ou não. Se for inválida, exibe-se a visualização [erreurs]. Essa vista contém o controle [ValidationSummary], que herda os atributos [ErrorMessage] de todos os controles (veja a captura de tela acima). Se a página for válida, é exibida a vista [infos] com uma mensagem informativa.
- O procedimento [lnkErreursToFormulaire_Click] é responsável por exibir a visão [formulaire] no estado em que foi validada. Todos os campos de entrada da vista [formulaire] que possuem a propriedade [EnableViewState=true] têm seu estado regenerado automaticamente. Curiosamente, o estado dos componentes de validação não é restaurado. De fato, seria de se esperar que, ao retornar à vista [erreurs], os controles com erros exibissem seu campo [Text]. Mas não é o que ocorre. Portanto, forçamos a validação dos dados utilizando o método [Page.Validate] da página. Isso deve ser feito assim que o painel [vueFormulaire] for exibido. Portanto, há, no total, duas validações. Na prática, isso deve ser evitado. Neste caso, o exemplo nos permitiu introduzir novos conceitos sobre a validação de páginas.
8.3. Componentes ListControl e vinculação de dados
Alguns dos componentes de servidor analisados permitem exibir uma lista de valores (DropDownList, ListBox). Outros, que ainda não apresentamos, permitem exibir várias listas de valores em tabelas HTML. Para todos eles, é possível, por meio de programa, associar, um por um, os valores das listas ao componente correspondente. Também é possível associar objetos mais complexos a esses componentes, como objetos do tipo [Array], [ArrayList], [DataSet], [HashTable], ... o que simplifica o código que associa os dados ao componente. Essa associação é chamada de ligação de dados.
Todos os componentes derivados da classe [ListControl] podem ser associados a uma lista de dados. Trata-se dos componentes [DropDownList], [ListBox], [CheckButtonList], [RadioButtonList]. Cada um desses componentes pode ser vinculado a uma fonte de dados. Essa fonte pode ser diversa: [Array], [ArrayList], [DataTable], [DataSet], [HashTable],...., em geral, um objeto que implemente uma das interfaces IEnumerable, ICollection, IListSource. Apresentaremos apenas alguns deles. Um objeto [DataSet] é um objeto de imagem de um banco de dados relacional. Trata-se, portanto, de um conjunto de tabelas interligadas por relações. O objeto [DataTable] representa uma dessas tabelas. A fonte de dados define as propriedades [Text] e [Value] de cada um dos membros [Item] do objeto [ListControl]. Se T for o valor de [Text] e V o valor de [Value], a tag HTML gerada para cada elemento de [ListControl] é a seguinte:
<option value="V">T</option> | |
<input type="checkbox" value="V">T | |
<input type="radio" value="V">T |
A associação de um componente [ListControl] a uma fonte de dados é feita por meio das seguintes propriedades:
uma fonte de dados [Array], [ArrayList], [DataTable], [DataSet], [HashTable], ... | |
no caso em que a fonte de dados for um [DataSet], representa o nome da tabela a ser utilizada como fonte de dados. A verdadeira fonte de dados é, portanto, uma tabela. | |
no caso em que a fonte de dados for uma tabela ([DataTable], [DataSet]), representa o nome da coluna da tabela que fornecerá seus valores ao campo [Text] dos elementos do [ListControl] | |
no caso em que a fonte de dados for uma tabela ([DataTable], [DataSet]), representa o nome da coluna da tabela que fornecerá seus valores ao campo [Value] dos elementos de [ListControl] |
A associação de um componente [ListControl] a uma fonte de dados não inicializa o componente com os valores da fonte de dados. Essa tarefa é realizada pela operação [ListControl].DataBind.
Dependendo da natureza da fonte de dados, a associação desta a um componente [ListControl] ocorrerá de maneira diferente:
[ListControl].DataSource=A os campos [Text] e [Value] dos elementos de [ListControl] terão como valores os elementos de A | |
[ListControl].DataSource=AL os campos [Text] e [Value] dos elementos de [ListControl] terão como valores os elementos de AL | |
[ListControl].DataSource=DT, [ListControl].DataTextField="col1", [ListControl]. DatavalueField ="col2" onde col1 e col2 são duas colunas da tabela DT. Os campos [Text] e [Value] dos elementos de [ListControl] terão como valores os das colunas col1 e col2 da tabela DT | |
[ListControl].DataSource=DS, [ListControl].DataSource="table", em que "table" é o nome de uma das tabelas de DS. [ListControl].DataTextField="col1", [ListControl]. DatavalueField ="col2", em que col1 e col2 são duas colunas da tabela "table". Os campos [Text] e [Value] dos elementos de [ListControl] terão como valores os das colunas col1 e col2 da tabela “table” | |
[ListControl].DataSource=HT, [ListControl].DataTextField="key", [ListControl]. DatavalueField ="value", em que [key] e [value] são, respectivamente, as chaves e os valores de HT. |
Vamos aplicar essas informações ao exemplo a seguir, [databind1.aspx]:
![]() |
Temos aqui cinco ligações de dados, cada uma com quatro controles do tipo [DropDownList], [ListBox], [CheckBoxList] e [RadioButtonList]. As cinco ligações analisadas diferem em suas fontes de dados:
conexão | fonte de dados |
Matriz | |
ArrayList | |
DataTable | |
DataSet | |
HashTable |
8.3.1. Código de apresentação dos componentes
O código de apresentação dos controles da ligação 1 é o seguinte:
<td>
<asp:DropDownList id="DropDownList1" runat="server"></asp:DropDownList>
</td>
<td>
<asp:ListBox id="ListBox1" runat="server" SelectionMode="Multiple"></asp:ListBox>
</td>
<td>
<asp:CheckBoxList id="CheckBoxList1" runat="server"></asp:CheckBoxList>
</td>
<td>
<asp:RadioButtonList id="RadioButtonList1" runat="server"></asp:RadioButtonList>
</td>
O das ligações 2 a 5 é idêntico, exceto pelo número da ligação.
8.3.2. Ligação a uma fonte de dados do tipo Array
A ligação dos quatro controles [ListBox] acima é feita da seguinte maneira no procedimento [Page_Load] do código de controle:
' os dados globais
dim textes() as string={"un","deux","trois","quatre"}
dim valeurs() as string={"1","2","3","4"}
dim myDataListe as new ArrayList
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
dim myHashTable as new HashTable
' procedimento executado ao carregar a página
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' criam-se as fontes dos dados que serão vinculados aos componentes
createDataSources
' vinculação a uma tabela [Array]
bindToArray
' vinculação a uma lista [ArrayList]
bindToArrayList
' vinculação a uma tabela [DataTable]
bindToDataTable
' vínculo a um grupo de dados [DataSet]
bindToDataSet
' ligação a um dicionário [HashTable]
bindToHashTable
end if
End Sub
sub createDataSources
' cria as fontes de dados que serão vinculadas aos componentes
' arraylist
dim i as integer
for i=0 to textes.length-1
myDataListe.add(textes(i))
next
' tabela de dados
' define-se suas duas colunas
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
' preenche-se a tabela
dim ligne as DataRow
for i=0 to textes.length-1
ligne=myDataTable.NewRow
ligne("id")=i
ligne("texte")=textes(i)
myDataTable.Rows.Add(ligne)
next
' conjunto de dados — uma única tabela
myDataSet.Tables.Add(myDataTable)
' tabela de hash
for i=0 to textes.length-1
myHashTable.add(valeurs(i),textes(i))
next
end sub
' vinculação de tabela
sub bindToArray
' a associação aos componentes
with DropDownList1
.DataSource=textes
.DataBind
end with
with ListBox1
.DataSource=textes
.DataBind
end with
with CheckBoxList1
.DataSource=textes
.DataBind
end with
with RadioButtonList1
.DataSource=textes
.DataBind
end with
' seleção dos elementos
ListBox1.Items(1).Selected=true
ListBox1.Items(3).Selected=true
CheckBoxList1.Items(0).Selected=true
CheckBoxList1.Items(3).Selected=true
DropDownList1.SelectedIndex=2
RadioButtonList1.SelectedIndex=1
end sub
sub bindToArrayList
....
end sub
sub bindToDataTable
...
end sub
sub bindToDataSet
...
end sub
A vinculação dos controles aos dados ocorre aqui apenas na primeira consulta. Posteriormente, os controles manterão seus elementos por meio do mecanismo [VIEWSTATE]. A vinculação é feita no procedimento [bindToArray]. Como a fonte de dados é do tipo [Array], apenas o campo [DataSource] dos componentes [ListControl] é inicializado. O preenchimento do controle com os valores da fonte de dados associada é realizado pelo método [ListControl].DataBind. Somente depois disso é que os objetos [ListControl] passam a conter elementos. É possível, então, selecionar alguns deles.
8.3.3. Ligação a uma fonte de dados do tipo ArrayList
A fonte de dados [myDataListe] é inicializada no procedimento [createDataSources]:
' dados globais
dim textes() as string={"un","deux","trois","quatre"}
dim myDataListe as new ArrayList
..
' procedimento executado ao carregar a página
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' são criadas as fontes de dados que serão vinculadas aos componentes
createDataSources
...
end if
End Sub
sub createDataSources
' cria as fontes de dados que serão vinculadas aos componentes
' arraylist
dim i as integer
for i=0 to textes.length-1
myDataListe.add(textes(i))
next
...
end sub
A ligação dos quatro controles [ListBox] da ligação 2 é feita da seguinte maneira no procedimento [bindToArrayList] do código de controle:
' vinculação da arraylist
sub bindToArrayList
' a associação aos componentes
with DropDownList2
.DataSource=myDataListe
.DataBind
end with
with ListBox2
.DataSource=myDataListe
.DataBind
end with
with CheckBoxList2
.DataSource=myDataListe
.DataBind
end with
with RadioButtonList2
.DataSource=myDataListe
.DataBind
end with
' a seleção dos elementos
ListBox2.Items(1).Selected=true
ListBox2.Items(3).Selected=true
CheckBoxList2.Items(0).Selected=true
CheckBoxList2.Items(3).Selected=true
DropDownList2.SelectedIndex=2
RadioButtonList2.SelectedIndex=1
end sub
Como a fonte de dados é do tipo [ArrayList], apenas o campo [DataSource] dos componentes [ListControl] é inicializado.
8.3.4. Fonte de dados do tipo DataTable
A fonte de dados [myDataTable] é inicializada no procedimento [createDataSources]:
' os dados globais
dim textes() as string={"un","deux","trois","quatre"}
dim myDataTable as new DataTable("table1")
...
' procedimento executado ao carregar a página
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' são criadas as fontes de dados que serão vinculadas aos componentes
createDataSources
...
end if
End Sub
sub createDataSources
' cria as fontes de dados que serão vinculadas aos componentes
...
' tabela de dados
' definem-se suas duas colunas
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
' preenche-se a tabela
dim ligne as DataRow
for i=0 to textes.length-1
ligne=myDataTable.NewRow
ligne("id")=i
ligne("texte")=textes(i)
myDataTable.Rows.Add(ligne)
next
...
end sub
Começamos criando um objeto [DataTable] com duas colunas: [id] e [texte]. A coluna [id] preencherá o campo [Value] dos elementos de [ListControl], e a coluna [texte] preencherá seus campos [Text]. A construção do [DataTable] com duas colunas é feita da seguinte maneira:
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
Cria-se, portanto, uma tabela com duas colunas:
- a primeira, chamada “id”, é do tipo inteiro
- a segunda, chamada “texto”, é do tipo string
Com a estrutura da tabela criada, podemos preenchê-la com o código a seguir:
dim ligne as DataRow
for i=0 to textes.length-1
ligne=myDataTable.NewRow
ligne("id")=i
ligne("texte")=textes(i)
myDataTable.Rows.Add(ligne)
next
A coluna [id] conterá números inteiros de [0,1,..,n], enquanto a coluna [texte] conterá os valores da tabela [data]. Feito isso, a tabela [dataListe] é preenchida. A ligação dos quatro controles [ListBox] da ligação 3 é feita da seguinte maneira no procedimento [bindToDataTable] do código de controle:
sub bindToDataTable
' a associação aos componentes
with DropDownList3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with ListBox3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with CheckBoxList3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with RadioButtonList3
.DataSource=myDataTable
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
' a seleção dos elementos
ListBox3.Items(1).Selected=true
ListBox3.Items(3).Selected=true
CheckBoxList3.Items(0).Selected=true
CheckBoxList3.Items(3).Selected=true
DropDownList3.SelectedIndex=2
RadioButtonList3.SelectedIndex=1
end sub
Cada componente [ListControl] está vinculado à fonte [myDataTable], atribuindo a cada um deles:
A tabela [myDataTable] é a fonte de dados. A coluna [id] dessa tabela preencherá os campos [Value] dos elementos dos componentes, enquanto a coluna [texte] preencherá seus campos [Text].
8.3.5. Fonte de dados do tipo DataSet
A fonte de dados [myDataSet] é inicializada no procedimento [createDataSources]:
' os dados globais
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
...
' procedimento executado ao carregar a página
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' criam-se as fontes de dados que serão vinculadas aos componentes
createDataSources
...
end if
End Sub
sub createDataSources
' cria as fontes de dados que serão vinculadas aos componentes
' conjunto de dados — uma única tabela
myDataSet.Tables.Add(myDataTable)
...
end sub
Um objeto [DataSet] representa um conjunto de tabelas do tipo [DataTable]. Adiciona-se a tabela [myDataTable], criada anteriormente, à [DataSet]. A ligação dos quatro controles [ListBox] da ligação 4 é feita da seguinte maneira no procedimento [bindToDataSet] do código de controle:
sub bindToDataSet
' a associação aos componentes
with DropDownList4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with ListBox4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with CheckBoxList4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
with RadioButtonList4
.DataSource=myDataSet
.DataMember="table1"
.DataValueField="id"
.DataTextField="texte"
.DataBind
end with
' a seleção dos elementos
ListBox4.Items(1).Selected=true
ListBox4.Items(3).Selected=true
CheckBoxList4.Items(0).Selected=true
CheckBoxList4.Items(3).Selected=true
DropDownList4.SelectedIndex=2
RadioButtonList4.SelectedIndex=1
end sub
Cada componente [ListControl] está vinculado à fonte de dados da seguinte maneira:
O grupo de dados [myDataSet] é a fonte de dados. Como essa fonte pode incluir várias tabelas, especifica-se em [DataMember] o nome da tabela que será utilizada. A coluna [id] dessa tabela preencherá os campos [Value] dos elementos dos componentes, enquanto a coluna [texte] preencherá seus campos [Text].
8.3.6. Fonte de dados do tipo HashTable
A fonte de dados [myHashTable] é inicializada no procedimento [createDataSources]:
' os dados globais
dim textes() as string={"un","deux","trois","quatre"}
dim valeurs() as string={"1","2","3","4"}
dim myHashTable as new HashTable
...
' procedimento executado ao carregar a página
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' são criadas as fontes de dados que serão vinculadas aos componentes
createDataSources
...
end if
End Sub
sub createDataSources
' cria as fontes de dados que serão vinculadas aos componentes
...
' tabela hash
for i=0 to textes.length-1
myHashTable.add(valeurs(i),textes(i))
next
end sub
O dicionário [myHashTable] pode ser visto como uma tabela com duas colunas chamadas “chave” e “valor”. A coluna [key] representa as chaves do dicionário e a coluna [value], os valores associados a elas. A coluna [key] é formada pelo conteúdo da tabela [valeurs], e a coluna [value], pelo conteúdo da tabela [textes]. A ligação dessa fonte aos controles é feita no procedimento [bindToHashTable]:
sub bindToHashTable
' a associação aos componentes
with DropDownList5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
with ListBox5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
with CheckBoxList5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
with RadioButtonList5
.DataSource=myHashTable
.DataValueField="key"
.DataTextField="value"
.DataBind
end with
' a seleção dos elementos
ListBox5.Items(1).Selected=true
ListBox5.Items(3).Selected=true
CheckBoxList5.Items(0).Selected=true
CheckBoxList5.Items(3).Selected=true
DropDownList5.SelectedIndex=2
RadioButtonList5.SelectedIndex=1
end sub
Para cada um dos componentes, a ligação é feita por meio das instruções:
A fonte de dados é o dicionário [myHashTable]. Os valores dos controles são fornecidos pela coluna [key] do dicionário e os textos pela coluna [value]. A inserção dos elementos do dicionário nos controles ocorre na ordem das chaves, que é, a princípio, aleatória.
8.3.7. Diretrizes para importação de espaços de nomes
Vários espaços de nomes são importados automaticamente para uma página ASP.NET. Esse não é o caso de “System.Data”, onde se encontram as classes [DataTable] e [DataSet]. Portanto, é necessário importar essa classe. Isso é feito da seguinte maneira:
<%@ Page Language="VB" %>
<%@ import Namespace="System.Data" %>
<script runat="server">
...
</script>
<html>
...
</html>
8.4. Componente DataGrid e conexão de dados
O componente [DataGrid] permite exibir dados na forma de tabelas, mas vai muito além dessa simples exibição:
- ele oferece a possibilidade de configurar com precisão a “apresentação visual” da tabela
- permite a atualização da fonte de dados
O componente [DataGrid] é um componente ao mesmo tempo poderoso e complexo. Vamos apresentá-lo passo a passo.
8.4.1. Exibição de uma fonte de dados do tipo Array: ArrayList, DataTable, DataSet
O componente [DataGrid] permite exibir em uma tabela HTML fontes de dados dos tipos [Array], [ArrayList], [DataTable] e [DataSet]. Para esses quatro tipos de dados, basta associar a fonte à propriedade [DataSource] do componente [DataGrid]:
uma fonte de dados [Array], [ArrayList], [DataTable], [DataSet], ... | |
no caso em que a fonte de dados for um [DataSet], representa o nome da tabela a ser utilizada como fonte de dados. A verdadeira fonte de dados é, então, uma tabela. Se este campo não for preenchido, todas as tabelas do [DataSet] serão exibidas. |
Apresentamos agora a página [datagrid1.aspx], que mostra a associação de um [DataGrid] a quatro fontes de dados diferentes:

A página contém quatro componentes [DataGrid] criados com o [WebMatrix] da seguinte maneira. O componente é inserido em seu local na aba [Design]:

Em seguida, é desenhada uma tabela HTML genérica. As propriedades de um [DataGrid] podem ser definidas durante o projeto. É isso que fazemos aqui para suas propriedades de formatação. Para isso, selecionamos o [DataGrid] a ser configurado. Suas propriedades aparecem em uma janela no canto inferior direito:

Vamos utilizar os dois links acima. O link [Générateur de propriétés] dá acesso às principais propriedades do [DataGrid]:

Desmarcamos a opção [Afficher l'en-tête] para os quatro componentes [DataGrid] e salvamos a página. O outro link, [Mise en forme automatique], permite escolher entre vários estilos para a tabela HTML que será exibida:

Escolhemos [couleur i] para o [DataGrid] n.º i. Essas escolhas de design são traduzidas no código de apresentação da página:
<html>
<head>
</head>
<body>
<form runat="server">
<p>
Liaison de données avec un DataGrid
</p>
<hr />
<p>
<table>
<tbody>
</tbody>
</table>
<table border="1">
<tbody>
<tr>
<td>
Array</td>
<td>
ArrayList</td>
<td>
DataTable</td>
<td>
DataSet</td>
</tr>
<tr>
<td>
<asp:DataGrid id="DataGrid1" runat="server" ShowHeader="False" CellPadding="4" BackColor="White" BorderColor="#CC9966" BorderWidth="1px" BorderStyle="None">
<FooterStyle forecolor="#330099" backcolor="#FFFFCC"></FooterStyle>
<HeaderStyle font-bold="True" forecolor="#FFFFCC" backcolor="#990000"></HeaderStyle>
<PagerStyle horizontalalign="Center" forecolor="#330099" backcolor="#FFFFCC"></PagerStyle>
<SelectedItemStyle font-bold="True" forecolor="#663399" backcolor="#FFCC66"></SelectedItemStyle>
<ItemStyle forecolor="#330099" backcolor="White"></ItemStyle>
</asp:DataGrid>
</td>
<td>
<asp:DataGrid id="DataGrid2" runat="server" ShowHeader="False" CellPadding="4" BackColor="White" BorderColor="#3366CC" BorderWidth="1px" BorderStyle="None">
<FooterStyle forecolor="#003399" backcolor="#99CCCC"></FooterStyle>
<HeaderStyle font-bold="True" forecolor="#CCCCFF" backcolor="#003399"></HeaderStyle>
<PagerStyle horizontalalign="Left" forecolor="#003399" backcolor="#99CCCC" mode="NumericPages"></PagerStyle>
<SelectedItemStyle font-bold="True" forecolor="#CCFF99" backcolor="#009999"></SelectedItemStyle>
<ItemStyle forecolor="#003399" backcolor="White"></ItemStyle>
</asp:DataGrid>
</td>
<td>
<asp:DataGrid id="DataGrid3" runat="server" ShowHeader="False" CellPadding="3" BackColor="#DEBA84" BorderColor="#DEBA84" BorderWidth="1px" BorderStyle="None" CellSpacing="2">
<FooterStyle forecolor="#8C4510" backcolor="#F7DFB5"></FooterStyle>
<HeaderStyle font-bold="True" forecolor="White" backcolor="#A55129"></HeaderStyle>
<PagerStyle horizontalalign="Center" forecolor="#8C4510" mode="NumericPages"></PagerStyle>
<SelectedItemStyle font-bold="True" forecolor="White" backcolor="#738A9C"></SelectedItemStyle>
<ItemStyle forecolor="#8C4510" backcolor="#FFF7E7"></ItemStyle>
</asp:DataGrid>
</td>
<td>
<asp:DataGrid id="DataGrid4" runat="server" ShowHeader="False" CellPadding="3" BackColor="White" BorderColor="#E7E7FF" BorderWidth="1px" BorderStyle="None" GridLines="Horizontal">
<FooterStyle forecolor="#4A3C8C" backcolor="#B5C7DE"></FooterStyle>
<HeaderStyle font-bold="True" forecolor="#F7F7F7" backcolor="#4A3C8C"></HeaderStyle>
<PagerStyle horizontalalign="Right" forecolor="#4A3C8C" backcolor="#E7E7FF" mode="NumericPages"></PagerStyle>
<SelectedItemStyle font-bold="True" forecolor="#F7F7F7" backcolor="#738A9C"></SelectedItemStyle>
<AlternatingItemStyle backcolor="#F7F7F7"></AlternatingItemStyle>
<ItemStyle forecolor="#4A3C8C" backcolor="#E7E7FF"></ItemStyle>
</asp:DataGrid>
</td>
</tr>
</tbody>
</table>
</p>
<asp:Button id="Button1" runat="server" Text="Envoyer"></asp:Button>
</form>
</body>
</html>
No modo de design, definimos apenas propriedades de formatação. É no código de controle que associamos dados aos quatro componentes:
<%@ Page Language="VB" %>
<%@ import Namespace="system.data" %>
<script runat="server">
' dados gerais
dim textes1() as string={"un","deux","trois","quatre"}
dim textes2() as string={"one","two","three","for"}
dim valeurs() as string={"1","2","3","4"}
dim myDataListe as new ArrayList
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
' procedimento executado ao carregar a página
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' são criadas as fontes dos dados que serão vinculados aos componentes
createDataSources
' vinculação a uma tabela [Array]
bindToArray
' vinculação a uma lista [ArrayList]
bindToArrayList
' vinculação a uma tabela [DataTable]
bindToDataTable
' vinculação a um grupo de dados [DataSet]
bindToDataSet
end if
End Sub
sub createDataSources
' cria as fontes de dados que serão vinculadas aos componentes
' arraylist
dim i as integer
for i=0 to textes1.length-1
myDataListe.add(textes1(i))
next
' tabela de dados
' define-se suas duas colunas
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte1",Type.GetType("System.String"))
myDataTable.Columns.Add("texte2",Type.GetType("System.String"))
' preenche-se a tabela
dim ligne as DataRow
for i=0 to textes1.length-1
ligne=myDataTable.NewRow
ligne("id")=valeurs(i)
ligne("texte1")=textes1(i)
ligne("texte2")=textes2(i)
myDataTable.Rows.Add(ligne)
next
' conjunto de dados — uma única tabela
myDataSet.Tables.Add(myDataTable)
end sub
' vinculação de tabela
sub bindToArray
with DataGrid1
.DataSource=textes1
.DataBind
end with
end sub
' ligação de arraylist
sub bindToArrayList
with DataGrid2
.DataSource=myDataListe
.DataBind
end with
end sub
' ligação de datatable
sub bindToDataTable
with DataGrid3
.DataSource=myDataTable
.DataBind
end with
end sub
' vinculação de conjunto de dados
sub bindToDataSet
with DataGrid4
.DataSource=myDataSet
.DataBind
end with
end sub
</script>
<html>
...
</html>
O código é bastante semelhante ao do exemplo anterior, portanto não faremos comentários específicos sobre ele. Observemos, no entanto, como a vinculação de dados é feita. Para cada um dos quatro controles, basta a seguinte sequência:
onde [source de données] é do tipo [Array] ou [ArrayList] ou [DataTable] ou [DataSet]. Vemos, portanto, que temos aqui uma ferramenta poderosa para exibir dados em tabelas:
- a formatação é feita com [WebMatrix] ou qualquer outro IDE no momento do projeto
- a vinculação de dados é feita no código. Com o [WebMatrix], ela pode ser feita na fase de concepção se a fonte de dados for um servidor de banco de dados SQL ou um banco de dados ACCESS. Nesse caso, deve-se inserir um componente do tipo [SqlDataSource] ou [AccessDataSource] na folha. Esse componente pode ser vinculado, no momento do projeto, à fonte física dos dados, seja um servidor SQL ou um servidor ACCESS, conforme o caso. Se for atribuído à propriedade [DataSource] de um componente [DataGrid] um objeto [SqlDataSource] ou [AccessDataSource] vinculado a uma fonte física, então aparecerão, no modo de projeto, os dados reais no componente [DataGrid].
8.5. ViewState dos componentes de listas de dados
Propomos aqui destacar o mecanismo do [VIEWSATE] para os componentes de listas de dados. É possível hesitar entre dois métodos para manter o estado de um componente de lista de dados entre duas solicitações do cliente:
- definir seu atributo [VIEWSTATE] como verdadeiro
- definir seu atributo [VIEWSTATE] como falso e armazenar sua fonte de dados na sessão, a fim de poder vincular o componente a essa fonte na próxima solicitação.
O exemplo a seguir ilustra alguns aspectos do mecanismo [VIEWSTATE] dos contêineres de dados. Na primeira solicitação do cliente, o aplicativo exibe a seguinte visualização:
![]() |
n.º | nome | tipo | propriedades | função |
1 | DataGrid | EnableViewState=true | exibe uma fonte de dados S | |
2 | DataGrid | EnableViewState=true | exibe a mesma fonte S que [DataGrid1] | |
3 | Botão | EnableViewState=false | botão [submit] |
O componente [DataGrid1] é mantido pelo mecanismo do [VIEWSTATE]. Deseja-se verificar se esse mecanismo, que atualiza a exibição do [DataGrid1] a cada solicitação, também atualiza sua fonte de dados. Para isso, esta está vinculada ao componente [DataGrid2]. A geração deste a cada consulta é feita por meio de uma ligação explícita à fonte de dados do [DataGrid1]. Ele também possui o atributo [EnableViewState] vinculado ao [vrai].
O código de apresentação [main.aspx] do aplicativo é o seguinte:
<%@ page src="main.aspx.vb" inherits="main" autoeventwireup="false" %>
<HTML>
<HEAD>
<title></title>
</HEAD>
<body>
<form runat="server">
<table>
<tr>
<td align="center">DataGrid 1</td>
<td align="center">
DataGrid 2</td>
</tr>
<tr>
<td>
<asp:DataGrid id="DataGrid1" runat="server" ...>
<SelectedItemStyle ...></SelectedItemStyle>
....
</asp:DataGrid></td>
<td>
<asp:DataGrid id="Datagrid2" runat="server" ...>
....
</asp:DataGrid></td>
</tr>
</table>
<asp:Button id="Button1" runat="server" Text="Envoyer"></asp:Button>
</form>
</body>
</HTML>
O controlador [main.aspx.vb] é o seguinte:
Imports System.Data
Public Class main
Inherits System.Web.UI.Page
Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid
Protected WithEvents Datagrid2 As System.Web.UI.WebControls.DataGrid
Protected WithEvents Button1 As System.Web.UI.WebControls.Button
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' na primeira consulta, a fonte de dados é definida e vinculada à primeira grade de dados
If Not IsPostBack Then
'definir a fonte de dados
With DataGrid1
.DataSource = createDataSource()
.DataBind()
End With
End If
' a cada consulta, vincula-se a grade de dados 2 à fonte da primeira grade de dados
With Datagrid2
.DataSource = DataGrid1.DataSource
.DataBind()
End With
End Sub
Private Function createDataSource() As DataTable
' inicializa-se a fonte de dados
Dim thèmes As New DataTable
' colunas
With thèmes.Columns
.Add("id", GetType(System.Int32))
.Add("thème", GetType(System.String))
.Add("description", GetType(System.String))
End With
' a coluna id será a chave primária
thèmes.Constraints.Add("cléprimaire", thèmes.Columns("id"), True)
' linhas
Dim ligne As DataRow
For i As Integer = 0 To 4
ligne = thèmes.NewRow
ligne.Item("id") = i.ToString
ligne.Item("thème") = "thème" + i.ToString
ligne.Item("description") = "description du thème " + i.ToString
thèmes.Rows.Add(ligne)
Next
Return thèmes
End Function
Private Sub InitializeComponent()
End Sub
End Class
O método [createDataSource] cria uma fonte S do tipo [DataTable]. Não nos deteremos em seu código, que não é o foco deste exemplo. O que nos interessa é a maneira como são construídos os dois componentes [DataGrid]:
- o componente [DataGrid1] é vinculado uma vez à tabela S, durante a primeira consulta. Depois disso, não há mais essa vinculação.
- o componente [DataGrid2] é vinculado à fonte [DataGrid1.DataSource] a cada nova consulta.
Na primeira consulta, obtemos a seguinte visualização:

Como era de se esperar, os dois componentes exibem a fonte de dados à qual foram vinculados. Utilizamos o botão [Envoyer] para enviar uma solicitação [PostBack] ao servidor. A visualização obtida é então a seguinte:

Observamos que o componente [DataGrid1] manteve seu valor, mas não o componente [DataGrid2]. Explicações:
- antes mesmo de o procedimento [Page_Load] ser iniciado, os objetos [DataGrid1] e [DataGrid2] recuperaram o valor que possuíam na consulta anterior, devido ao mecanismo do [viewstate]. De fato, ambos têm sua propriedade [EnableViewState] definida como [vrai].
- O procedimento [Page_Load] é executado. Como se trata de uma operação [PostBack], o componente [DataGrid1] não é alterado pelo [Page_Load] (ver código). Portanto, ele mantém o valor recuperado por meio do [viewstate]. É o que mostra a tela acima.
- O componente [DataGrid2], por sua vez, está vinculado ao [DataBind] e à fonte de dados [DataGrid1.DataSource]. Assim, ele é reconstruído e o valor que acabara de recuperar por meio do [viewstate] é perdido. Portanto, teria sido vantajoso que ele tivesse sua propriedade [EnableViewState] vinculada a [faux], a fim de evitar o gerenciamento desnecessário de seu estado. A tela acima mostra que [DataGrid2] foi vinculado a uma fonte vazia. Sendo essa fonte [DataGrid1.DataSource], deduz-se que, embora o mecanismo do [viewstate] restaure corretamente a exibição do componente [DataGrid1], ele não restaura suas propriedades, como a [DataSource].
O que podemos concluir desse exemplo? É preciso evitar definir a propriedade [EnableViewState] de um contêiner de dados como [vrai] se ele precisar ser vinculado (DataBind) a uma fonte de dados a cada consulta. No entanto, há certos casos em que, mesmo nessa situação, a propriedade [EnableViewState] do contêiner deve ser mantida em [vrai]; caso contrário, os eventos que se deseja gerenciar não serão acionados. Teremos a oportunidade de ver um exemplo disso.
Frequentemente, a fonte de dados de um contêiner de dados muda ao longo das consultas. Portanto, a cada consulta, é necessário vincular o contêiner à fonte de dados. É comum que esta seja mantida na sessão para que as consultas tenham acesso a ela. Nosso segundo exemplo ilustra esse mecanismo. O aplicativo fornece apenas uma única visualização:
![]() |
n.º | nome | tipo | propriedades | função |
1 | DataGrid | EnableViewState=true | exibe uma fonte de dados S | |
2 | DataGrid | EnableViewState=false | exibe a mesma fonte S que [DataGrid1] | |
3 | Botão | EnableViewState=false | botão [submit] | |
4 | Rótulo | EnableViewState=false | textos informativos |
O componente [DataGrid1] é vinculado aos dados apenas na primeira consulta. Ele manterá seu valor ao longo das consultas graças ao mecanismo do [viewstate]. O componente [DataGrid2] é vinculado a cada consulta a uma fonte de dados à qual é adicionado um elemento a cada nova consulta. Portanto, é necessário vincular (DataBind) o componente [DataGrid2] a cada consulta. Portanto, definimos seu atributo [EnableViewState] como [faux], conforme recomendado anteriormente. Assim, na segunda consulta (uso do botão [Envoyer]), obtemos a seguinte resposta:

O componente [DataGrid1] manteve seu valor inicial. O componente [DataGrid2] possui um elemento a mais. As três informações [1,2,2] representam o número da consulta. Percebe-se que uma das informações está incorreta. Tentaremos entender o motivo.
O código de apresentação [main.aspx] do aplicativo é o seguinte:
<%@ Page src="main.aspx.vb" inherits="main" autoeventwireup="false" Language="vb" %>
<HTML>
<HEAD>
<title></title>
</HEAD>
<body>
<form runat="server">
<table>
<tr>
<td align="center" bgColor="#ccffcc">DataGrid 1</td>
<td align="center" bgColor="#ffff99">DataGrid 2</td>
</tr>
<tr>
<td vAlign="top">
<asp:DataGrid id="DataGrid1" runat="server" ...>
...
</asp:DataGrid>
</td>
<td vAlign="top">
<asp:DataGrid id="Datagrid2" runat="server" ... EnableViewState="False">
....
</asp:DataGrid>
</td>
</tr>
</table>
<P>Numéro de requête :
<asp:Label id="lblInfo1" runat="server" EnableViewState="False"></asp:Label>,
<asp:Label id="lblInfo2" runat="server" EnableViewState="False"></asp:Label>,
<asp:Label id="lblInfo3" runat="server" EnableViewState="False"></asp:Label></P>
<P>
<asp:Button id="Button1" runat="server" Text="Envoyer" EnableViewState="False"></asp:Button></P>
</form>
</body>
</HTML>
O código do controlador [main.aspx.vb] é o seguinte:
Imports System.Data
Imports System
Public Class main
Inherits System.Web.UI.Page
Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid
Protected WithEvents Datagrid2 As System.Web.UI.WebControls.DataGrid
Protected WithEvents Button1 As System.Web.UI.WebControls.Button
Protected WithEvents lblInfo1 As System.Web.UI.WebControls.Label
Protected WithEvents lblInfo2 As System.Web.UI.WebControls.Label
Protected WithEvents lblInfo3 As System.Web.UI.WebControls.Label
Dim dtThèmes As DataTable
Dim numRequête1 As Integer
Dim numRequête2 As Integer
Dim numRequête3 As New entier
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' na primeira consulta, a fonte de dados é definida e vinculada à primeira grade de dados
If Not IsPostBack Then
'definir a fonte de dados
dtThèmes = createDataSource()
With DataGrid1
.DataSource = dtThèmes
.DataBind()
End With
' armazenar informações na sessão
Session("source") = dtThèmes
numRequête1 = 0 : Session("numRequête1") = numRequête1
numRequête2 = 0 : Session("numRequête2") = numRequête2
numRequête3.valeur = 0 : Session("numRequête3") = numRequête3
End If
' a cada consulta, adiciona-se um novo tema
dtThèmes = CType(Session("source"), DataTable)
Dim nbThèmes = dtThèmes.Rows.Count
Dim ligne As DataRow = dtThèmes.NewRow
With ligne
.Item("id") = nbThèmes.ToString
.Item("thème") = "thème" + nbThèmes.ToString
.Item("description") = "description du thème " + nbThèmes.ToString
End With
dtThèmes.Rows.Add(ligne)
'vincula a grade de dados 2 à fonte de dados
With Datagrid2
.DataSource = dtThèmes
.DataBind()
End With
' informações sobre o número de consultas
numRequête1 = CType(Session("numRequête1"), Integer)
numRequête1 += 1
lblInfo1.Text = numRequête1.ToString
numRequête2 = CType(Session("numRequête2"), Integer)
numRequête2 += 1
lblInfo2.Text = numRequête2.ToString
numRequête3 = CType(Session("numRequête3"), entier)
numRequête3.valeur += 1
lblInfo3.Text = numRequête3.valeur.ToString
' armazenamos algumas informações na sessão
Session("numRequête2") = numRequête2
End Sub
Private Function createDataSource() As DataTable
....
End Function
End Class
Public Class entier
Private _valeur As Integer
Public Property valeur() As Integer
Get
Return _valeur
End Get
Set(ByVal Value As Integer)
_valeur = Value
End Set
End Property
End Class
Não reproduzimos o código do método [createDataSource]. É o mesmo da aplicação anterior, com a única diferença de que, no código-fonte, são incluídas apenas três linhas. Vamos nos concentrar, em primeiro lugar, no gerenciamento da fonte de dados e dos dois contêineres:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' na primeira consulta, a fonte de dados é definida e vinculada ao primeiro datagrid
If Not IsPostBack Then
'definir a fonte de dados
dtThèmes = createDataSource()
With DataGrid1
.DataSource = dtThèmes
.DataBind()
End With
' armazenar informações na sessão
Session("source") = dtThèmes
...
End If
' a cada consulta, adiciona-se um novo tema
dtThèmes = CType(Session("source"), DataTable)
Dim nbThèmes = dtThèmes.Rows.Count
Dim ligne As DataRow = dtThèmes.NewRow
With ligne
.Item("id") = nbThèmes.ToString
.Item("thème") = "thème" + nbThèmes.ToString
.Item("description") = "description du thème " + nbThèmes.ToString
End With
dtThèmes.Rows.Add(ligne)
'vincula o datagrid2 à fonte de dados
With Datagrid2
.DataSource = dtThèmes
.DataBind()
End With
...
End Sub
O componente [DataGrid1] é vinculado à fonte de dados S apenas na primeira consulta (não IsPostBack). Ele é então inserido na sessão. A partir daí, não será mais vinculado. A fonte de dados S inserida na sessão é recuperada a cada consulta e recebe uma nova linha. O componente [DataGrid2] é vinculado explicitamente, a cada consulta, à fonte S. É por isso que seu conteúdo aumenta em uma linha a cada consulta. Observa-se que, após modificar o conteúdo da fonte S, esta não é explicitamente colocada novamente na sessão por meio de uma operação:
Por quê? Quando uma solicitação é iniciada, a sessão contém um objeto Session("source") do tipo [DataTable], que é a fonte de dados tal como estava na última solicitação. Vamos chamar de S o objeto Session("source"). Quando escrevemos:
dtThèmes = CType(Session("source"), DataTable)
[dtThèmes] e [S] são duas referências a um mesmo objeto [DataTable]. Assim, quando o código de [Page_Load] adiciona um elemento à tabela referenciada por [dtThèmes], ele o adiciona, ao mesmo tempo, à tabela referenciada por [S]. Ao final da execução da página, todos os objetos presentes na sessão serão salvos e, portanto, o objeto Session("source"), c.a.d. S, c.a.d e [dtThèmes]. Portanto, é realmente o novo conteúdo da fonte de dados que é salvo. Não foi necessário escrever:
para realizar esse salvamento, pois Session("source") já é igual a [dtThèmes]. Isso não se aplica mais quando os dados armazenados na sessão não são objetos, como as estruturas [Integer, Float, ...]. É o que mostra o gerenciamento dos contadores de solicitações:
Dim numRequête1 As Integer
Dim numRequête2 As Integer
Dim numRequête3 As New entier
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' na primeira consulta, a fonte de dados é definida e vinculada ao primeiro datagrid
....
' armazenar informações na sessão
Session("source") = dtThèmes
numRequête1 = 0 : Session("numRequête1") = numRequête1
numRequête2 = 0 : Session("numRequête2") = numRequête2
numRequête3.valeur = 0 : Session("numRequête3") = numRequête3
End If
' a cada consulta, adiciona-se um novo tema
....
' informações sobre o número de consultas
numRequête1 = CType(Session("numRequête1"), Integer)
numRequête1 += 1
lblInfo1.Text = numRequête1.ToString
numRequête2 = CType(Session("numRequête2"), Integer)
numRequête2 += 1
lblInfo2.Text = numRequête2.ToString
numRequête3 = CType(Session("numRequête3"), entier)
numRequête3.valeur += 1
lblInfo3.Text = numRequête3.valeur.ToString
' armazenam-se algumas informações na sessão
Session("numRequête2") = numRequête2
End Sub
Private Function createDataSource() As DataTable
....
End Function
Private Sub InitializeComponent()
End Sub
End Class
Public Class entier
Private _valeur As Integer
Public Property valeur() As Integer
Get
Return _valeur
End Get
Set(ByVal Value As Integer)
_valeur = Value
End Set
End Property
Os contadores de solicitações são armazenados em três elementos:
- numRequête1 e numRequête2, do tipo [Integer] — [Integer] não é uma classe, mas uma estrutura
- numRequête3 do tipo [entier] — [entier] é uma classe definida especificamente para este caso
Quando se escreve:
numRequête1 = CType(Session("numRequête1"), Integer)
..
numRequête2 = CType(Session("numRequête2"), Integer)
..
numRequête3 = CType(Session("numRequête3"), entier)
..
- a estrutura [Session("numRequête1")] é copiada para [numRequête1]. Assim, quando o elemento [numRequête1] é modificado, o elemento [Session("numRequête1")], por sua vez, não é modificado
- o mesmo se aplica a [Session("numRequête2")] e [numRequête2]
- Os elementos [Session("numRequête3")] e [numRequête3] são, ambos, referências a um mesmo objeto do tipo [entier]. O objeto referenciado pode ser modificado indistintamente por qualquer uma das referências.
Diante disso, deduz-se que é desnecessário escrever:
para armazenar o novo valor de [numRequête3] na sessão. Por outro lado, seria necessário escrever:
para gravar os novos valores das estruturas [numRequête1] e [numRequête2]. Fazemos isso apenas para [numRequête2], o que explica por que, na captura de tela obtida após a segunda consulta, o contador [numRequête1] está incorreto.
Portanto, deve-se lembrar que, uma vez inserido na sessão, um dado não precisa ser reinserido repetidamente se for representado por um objeto. Nos demais casos, é necessário fazê-lo se o dado tiver sido modificado.
8.6. Exibição de uma lista de dados por meio de um DataGrid paginado e classificado
O componente [DataGrid] permite exibir o conteúdo de um [DataSet]. Até agora, sempre criamos nossos [DataSet] “manualmente”. Desta vez, utilizaremos um [DataSet] proveniente de um banco de dados. Criaremos a seguinte aplicação MVC:
![]() |
As três visualizações serão incorporadas ao código de apresentação do controlador [main.aspx] na forma de contêineres. Portanto, essa aplicação possui uma única página [main.aspx].
8.6.1. As classes de negócio
A classe [produits] fornece acesso ao banco de dados ACCESS a seguir:

O código da classe [produits] é o seguinte:
Imports System
Imports System.Data
Imports System.Data.OleDb
Imports System.Xml
Namespace st.istia.univangers.fr
Public Class produits
Private chaineConnexionOLEDB As String
Public Sub New(ByVal chaineConnexionOLEDB As String)
' armazena-se a string de conexão
Me.chaineConnexionOLEDB = chaineConnexionOLEDB
End Sub
Public Function getDataSet(ByVal commande As String) As DataSet
' cria-se um objeto DataAdapter para ler os dados da fonte OLEDB
Dim adaptateur As New OleDbDataAdapter(commande, chaineConnexionOLEDB)
' cria-se uma imagem em memória do resultado da consulta
Dim contenu As New DataSet
Try
adaptateur.Fill(contenu)
Catch e As Exception
Throw New Exception("Erreur d'accès à la base de données (" + e.Message + ")")
End Try
' retorna-se o resultado
Return contenu
End Function
End Class
End Namespace
O banco de dados ACCESS será gerenciado por meio do driver OLEDB. Fornece-se ao construtor da classe [produits] a string de conexão, o identificador, o driver OLEDB e o banco de dados a ser gerenciado. A classe [produits] possui um método [getDataSet] que retorna um [DataSet] obtido pela execução deuma consulta SQL [select], cujo texto é passado como parâmetro. Durante a execução do método, ocorrem várias operações: criação da conexão com o banco de dados, execução do [select] e fechamento da conexão. Tudo isso pode gerar uma exceção, que é tratada aqui. Um programa de teste poderia ser o seguinte:
Option Explicit On
Option Strict On
' espaços de nomes
Imports System
Imports System.Data
Imports Microsoft.VisualBasic
Namespace st.istia.univangers.fr
' página de teste
Module testproduits
Sub Main(ByVal arguments() As String)
' exibe o conteúdo de uma tabela de produtos
' a tabela está em um banco de dados ACCESS, cujo banco recebe o nome do arquivo
Const syntaxe1 As String = "pg bdACCESS"
' verificação dos parâmetros do programa
If arguments.Length <> 1 Then
' mensagem de erro
Console.Error.WriteLine(syntaxe1)
' fim
Environment.Exit(1)
End If
' preparação da cadeia de conexão
Dim chaineConnexion As String = "Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=" + arguments(0)
' criação de um objeto de produtos
Dim objProduits As produits = New produits(chaineConnexion)
' recuperando a tabela de produtos em um conjunto de dados
Dim contenu As DataSet
Try
contenu = objProduits.getDataSet("select id,nom,prix from liste")
Catch ex As Exception
Console.Error.WriteLine(("L'erreur suivante s'est produite : " + ex.Message))
Environment.Exit(2)
End Try
' exibindo seu conteúdo
Dim lignes As DataRowCollection = contenu.Tables(0).Rows
For i As Integer = 0 To lignes.Count - 1
' linha i da tabela
Console.Out.WriteLine(lignes(i).Item("id").ToString + "," + lignes(i).Item("nom").ToString + _
"," + lignes(i).Item("prix").ToString)
Next
End Sub
End Module
End Namespace
A compilação dos diversos elementos desta aplicação é feita da seguinte maneira:
dos>vbc /t:library /r:system.dll /r:system.data.dll /r:system.xml.dll produits.vb
dos>vbc /r:produits.dll /r:system.data.dll /r:system.xml.dll /r:system.dll testproduits.vb
dos>dir
06/05/2004 16:52 118 784 produits.mdb
07/05/2004 11:07 902 produits.vb
07/04/2004 07:01 1 532 testproduits.vb
07/05/2004 14:21 3 584 produits.dll
07/05/2004 14:22 4 608 testproduits.exe
dos>testproduits produits.mdb
1,produit1,10
2,produit2,20
3,produit3,30
8.6.2. As vistas
Agora que já temos a classe de acesso aos dados, vamos escrever os controladores e as visualizações dessa aplicação web. Vamos ver, antes de mais nada, como ela funciona. A primeira visualização é a seguinte:
![]() |
n.º | nome | tipo | propriedades | função |
1 | TextBox | EnableViewState=true | campo de entrada da consulta SELECT | |
2 | RequiredFieldValidator | EnableViewState=false | verifica se há 1 | |
3 | TextBox | EnableViewState=true | campo de entrada — indica o número de linhas de dados a serem exibidas por página de resultados | |
4 | RequiredFieldValidator | EnableViewState=false | verifica se há 3 | |
5 | RangeValidator | EnableViewState=false | verifica se (3) está no intervalo [1,30] | |
6 | Botão | EnableViewState=false | botão [submit] |
Chamaremos essa visualização de [formulaire]. Ela permite que o usuário execute uma consulta SELECT SQL no banco de dados [produits.mdb]. A execução da consulta gera uma nova visualização:
![]() |
n.º | nome | tipo | propriedades | função |
1 | Rótulo | EnableViewState=false | campo de informação | |
2 | RadioButton | EnableViewState=false GroupName=rdTri | permite escolher um sentido de classificação | |
3 | DataGrid | EnableViewState=true AllowPaging=true AllowSorting=true | tabela de exibição do resultado da consulta | |
4 | LinkButton | EnableViewState=false | botão-link [submit] |
Chamaremos essa visualização de [résultats]. É ela que contém o [DataGrid], que exibirá o resultado do comando select SQL. O usuário pode cometer um erro em sua consulta. Alguns erros serão sinalizados na visualização [erreurs] graças aos controles de validação.

Outros erros serão sinalizados na visualização [erreurs]:

A visualização [erreurs] é exibida:
![]() |
n.º | nome | tipo | propriedades | função |
1 | variável | código HTML necessário para a exibição de erros | ||
3 | LinkButton | EnableViewState=false | botão-link [submit] |
As três visualizações do aplicativo são três contêineres (painéis) diferentes dentro da mesma página [main.aspx]. Seu código de apresentação é o seguinte:
<%@ Page src="main.aspx.vb" inherits="main" autoeventwireup="false" Language="vb" %>
<HTML>
<HEAD>
</HEAD>
<body>
<P>Liaison de données avec un DataGrid</P>
<HR width="100%" SIZE="1">
<form runat="server">
<asp:panel id="vueFormulaire" runat="server">
<P>Commande [select] à exécuter sur la table LISTE</P>
<P> Exemple : select id, nom, prix from LISTE
</P>
<P>
<asp:TextBox id="txtSelect" runat="server" Columns="60"></asp:TextBox></P>
<P>
<asp:RequiredFieldValidator id="RequiredFieldValidator1" runat="server" EnableViewState="False" EnableClientScript="False"
ErrorMessage="Indiquez la requête [select] à exécuter" ControlToValidate="txtSelect" Display="Dynamic"></asp:RequiredFieldValidator></P>
<P>Nombre de lignes par page :
<asp:TextBox id="txtPages" runat="server" Columns="3"></asp:TextBox></P>
<P>
<asp:RequiredFieldValidator id="RequiredFieldValidator2" runat="server" EnableViewState="False" EnableClientScript="False"
ErrorMessage="Indiquez le nombre de lignes par page désirées" ControlToValidate="txtPages" Display="Dynamic"></asp:RequiredFieldValidator>
<asp:RangeValidator id="RangeValidator1" runat="server" EnableViewState="False" EnableClientScript="False"
ErrorMessage="Vous devez indiquer un nombre entre 1 et 30" ControlToValidate="txtPages" Display="Dynamic"
Type="Integer" MinimumValue="1" MaximumValue="30"></asp:RangeValidator></P>
<P>
<asp:Button id="btnExécuter" runat="server" EnableViewState="False" Text="Exécuter"></asp:Button></P>
</asp:panel>
<asp:Panel id="vueRésultats" runat="server">
<P>Résultats de la requête
<asp:Label id="lblSelect" runat="server"></asp:Label></P>
<P>Tri
<asp:RadioButton id="rdCroissant" runat="server" Text="croissant" Checked="True" GroupName="rdTri"></asp:RadioButton>
<asp:RadioButton id="rdDécroissant" runat="server" Text="décroissant" GroupName="rdTri"></asp:RadioButton></P>
<P>
<asp:DataGrid id="DataGrid1" runat="server" BorderColor="#CC9966" BorderStyle="None" BorderWidth="1px"
BackColor="White" CellPadding="4" AllowPaging="True" PageSize="4" AllowSorting="True">
<SelectedItemStyle Font-Bold="True" ForeColor="#663399" BackColor="#FFCC66"></SelectedItemStyle>
<ItemStyle ForeColor="#330099" BackColor="White"></ItemStyle>
<HeaderStyle Font-Bold="True" ForeColor="#FFFFCC" BackColor="#990000"></HeaderStyle>
<FooterStyle ForeColor="#330099" BackColor="#FFFFCC"></FooterStyle>
<PagerStyle NextPageText="Suivant" PrevPageText="Précédent" HorizontalAlign="Center"
ForeColor="#330099" BackColor="#FFFFCC"></PagerStyle>
</asp:DataGrid></P>
<P>
<asp:LinkButton id="lnkRésultats" runat="server" EnableViewState="False">Retour au formulaire</asp:LinkButton></P>
</asp:Panel>
<asp:Panel id="vueErreurs" runat="server">
<P>Les erreurs suivantes se sont produites :</P>
<% =erreursHTML %>
<P>
<asp:LinkButton id="lnkErreurs" runat="server" EnableViewState="False">Retour vers le formulaire</asp:LinkButton></P>
</asp:Panel>
</form>
</body>
</HTML>
8.6.3. Configuração do DataGrid
Vamos nos deter na paginação do componente [DataGrid], uma opção que encontramos pela primeira vez. No código acima, essa paginação é controlada pelos seguintes atributos:
<asp:DataGrid id="DataGrid1" runat="server" PageSize="4" AllowPaging="True" ...>
...
<PagerStyle NextPageText="Suivant" PrevPageText="Précédent" ...></PagerStyle>
</asp:DataGrid></P>
permite a paginação | |
quatro linhas de dados por página | |
O texto do link para acessar a próxima página da fonte de dados | |
O texto do link para acessar a página anterior da fonte de dados |
Essas informações podem ser inseridas diretamente nos atributos da tag <asp:datagrid>. Também é possível utilizar o [WebMatrix]. Na janela de propriedades do [DataGrid], acesse o link [Générateur de propriétés]:

Aparece o seguinte assistente:

Selecione a opção [Pagination]:

Encontramos acima os valores dos atributos de paginação do [DataGrid] do código de apresentação.
Além disso, permitimos a ordenação dos dados em uma das colunas do [DataGrid]. Existem diferentes maneiras de fazer isso. Uma delas é definir a propriedade [AllowSorting=true] na janela de propriedades do [DataGrid]. Também é possível usar o gerador de propriedades. Seja qual for o método utilizado, isso resulta na presença do atributo [AllowSorting=true] na tag <asp:DataGrid> do componente:
<asp:DataGrid id="DataGrid1" runat="server" ... AllowPaging="True" PageSize="4" AllowSorting="True">
8.6.4. Os controladores
O controlador [global.asax, global.asax.vb] é o seguinte:
[global.asax]
[global.asax.vb]
Imports st.istia.univangers.fr
Imports System.Configuration
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' criação de um objeto de produtos
Dim objProduits As produits
Try
objProduits = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection"))
' insere-se o objeto no aplicativo
Application("objProduits") = objProduits
' sem erros
Application("erreur") = False
Catch ex As Exception
'ocorreu um erro, que é registrado no aplicativo
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
End Class
Quando o aplicativo é iniciado (Application_Start), criamos um objeto [produits] e o inserimos no aplicativo para que esteja disponível para todas as solicitações de todos os clientes. Se ocorrer uma exceção durante essa criação, ela é registrada no aplicativo. O procedimento [Application_Start] será executado apenas uma vez. Depois disso, o controlador [global.asax] não será mais acionado. Será então o controlador [main.aspx.vb] que realizará o trabalho:
Imports System.Collections
Imports Microsoft.VisualBasic
Imports System.Data
Imports st.istia.univangers.fr
Imports System
Imports System.Xml
Public Class main
Inherits System.Web.UI.Page
' componentes da página
Protected WithEvents txtSelect As System.Web.UI.WebControls.TextBox
Protected WithEvents RequiredFieldValidator1 As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents txtPages As System.Web.UI.WebControls.TextBox
Protected WithEvents RequiredFieldValidator2 As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents RangeValidator1 As System.Web.UI.WebControls.RangeValidator
Protected WithEvents btnExécuter As System.Web.UI.WebControls.Button
Protected WithEvents vueFormulaire As System.Web.UI.WebControls.Panel
Protected WithEvents lblSelect As System.Web.UI.WebControls.Label
Protected WithEvents DataGrid1 As System.Web.UI.WebControls.DataGrid
Protected WithEvents lnkRésultats As System.Web.UI.WebControls.LinkButton
Protected WithEvents vueRésultats As System.Web.UI.WebControls.Panel
Protected WithEvents lnkErreurs As System.Web.UI.WebControls.LinkButton
Protected WithEvents vueErreurs As System.Web.UI.WebControls.Panel
Protected WithEvents rdCroissant As System.Web.UI.WebControls.RadioButton
Protected WithEvents rdDécroissant As System.Web.UI.WebControls.RadioButton
' dados da página
Protected erreursHTML As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' verifica-se se o aplicativo está com erro
If CType(Application("erreur"), Boolean) Then
' o aplicativo não foi inicializado corretamente
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs, False)
Exit Sub
End If
'1ª consulta
If Not IsPostBack Then
' exibe o formulário vazio
afficheFormulaire()
End If
End Sub
Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
' exibe a visualização de erros
erreursHTML = ""
For i As Integer = 0 To erreurs.Count - 1
erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
Next
lnkErreurs.Visible = afficheLien
' exibindo a visualização [erreurs]
vueErreurs.Visible = True
vueFormulaire.Visible = False
vueRésultats.Visible = False
End Sub
Private Sub afficheFormulaire()
' exibe a visualização [formulaire]
vueFormulaire.Visible = True
vueErreurs.Visible = False
vueRésultats.Visible = False
End Sub
Private Sub afficheRésultats(ByVal sqlTexte As String, ByVal données As DataView)
' inicializa os controles
lblSelect.Text = sqlTexte
With DataGrid1
.DataSource = données
.PageSize = CType(txtPages.Text, Integer)
.CurrentPageIndex = 0
.DataBind()
End With
' exibe a visualização [résultats]
vueRésultats.Visible = True
vueFormulaire.Visible = False
vueErreurs.Visible = False
End Sub
Private Sub btnExécuter_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnExécuter.Click
' a página está válida?
If Not Page.IsValid Then
afficheFormulaire()
Exit Sub
End If
' execução da consulta do cliente SELECT
Dim données As DataView
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0).DefaultView
Catch ex As Exception
Dim erreurs As New ArrayList
erreurs.Add("erreur d'accès à la base de données (" + ex.Message + ")")
afficheErreurs(erreurs, True)
Exit Sub
End Try
' tudo certo — exibindo os resultados
afficheRésultats(txtSelect.Text.Trim, données)
' os dados são inseridos na sessão
Session("données") = données
End Sub
Private Sub retourFormulaire(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkErreurs.Click, lnkRésultats.Click
' conjunto de visualizações
vueErreurs.Visible = False
vueFormulaire.Visible = True
vueRésultats.Visible = False
End Sub
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
' mudança de página
With DataGrid1
.CurrentPageIndex = e.NewPageIndex
.DataSource = CType(Session("données"), DataView)
.DataBind()
End With
End Sub
Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
' ordenando a visualização de dados
Dim données As DataView = CType(Session("données"), DataView)
données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
' exibindo
With DataGrid1
.CurrentPageIndex = 0
.DataSource = données
.DataBind()
End With
End Sub
End Class
Ao carregar a página [Page_Load], verificamos primeiro se o aplicativo conseguiu ser inicializado corretamente. Caso contrário, exibimos a visualização [erreurs] sem o link de retorno ao formulário, pois esse link se torna desnecessário. De fato, apenas a visualização [erreurs] pode ser exibida se a aplicação não tiver conseguido inicializar corretamente. Caso contrário, exibimos a visualização [formulaire] se estivermos lidando com a primeira solicitação do cliente. Quanto ao restante, deixamos a cargo do leitor a tarefa de compreender o código. Vamos nos concentrar apenas em três procedimentos: o procedimento [btnExécuter_Click], que é executado quando o usuário solicita a execução da consulta SQL inserida na visualização [formulaire], o procedimento [DataGrid1_PageIndexChanged], que é executado quando ousuário utiliza os links [Suivant] e [Précédent] da [DataGrid] e o procedimento [DataGrid1_SortCommand], que é executado quando o usuário clica no título de uma coluna para ordenar os dados de acordo com aordem da coluna. O sentido da ordem, crescente ou decrescente, é definido pelos dois botões de opção de classificação.
No procedimento [btnExécuter_Click], começa-se, portanto, verificando se a página é válida ou não. Quando o procedimento [btnExécuter_Click] é executado, as verificações relacionadas aos diversos controles de validação da página já foram realizadas. Para cada controle de validação, dois atributos foram definidos:
definido como verdadeiro se o dado verificado for válido, e como falso caso contrário | |
a mensagem de erro caso os dados verificados tenham sido considerados inválidos |
Para a própria página, foi definido um atributo [IsValid]. Ele será verdadeiro apenas se todos os controles de validação tiverem seu atributo [IsValid] definido como verdadeiro. Caso contrário, deve-se exibir a visualização [formulaire]. Esta contém os controles de validação que exibirão seu atributo [errorMessage]. Se a página for válida, utiliza-se o objeto do tipo [produits] criado por [Application_Start] para obter o [DataSet] correspondente à execução da consulta SQL select. Este é transformado no objeto [DataView]:
Dim données As DataView
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0).DefaultView
...
Poderíamos ter trabalhado simplesmente com o [DataSet] e escrito:
Dim données As DataSet
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim)
...
Um objeto [DataSet] é, na essência, um conjunto de tabelas interligadas por relações. Em nossa aplicação específica, o [DataSet] obtido a partir da classe [produits] contém apenas uma tabela, aquela resultante da instrução [select]. Uma tabela pode ser ordenada, ao passo que um [DataSet] não pode; no entanto, nosso interesse é ordenar os dados obtidos. Para trabalhar com a tabela resultante do [select], poderíamos ter escrito:
Dim données As DataTable
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0)
...
O objeto [DataTable], embora represente uma tabela de banco de dados, não possui um método de classificação. Para isso, é necessário ter uma visão da tabela. Uma visão é um objeto do tipo [DataView]. É possível ter diferentes visões de uma mesma tabela por meio de filtros. Uma tabela possui uma visualização padrão, que é aquela em que nenhum filtro está definido. Portanto, ela representa a tabela na íntegra. Essa visualização padrão é obtida por meio do [DataTable.DefaultView]. É possível ordenar uma visualização utilizando sua propriedade [sort], sobre a qual falaremos mais adiante.
Se a obtenção do [DataSet] da classe [produits] ocorrer sem problemas, a visualização [résultats] é exibida; caso contrário, é exibida a visualização [erreurs]. A exibição da vista [résultats] é feita pela procedimento [afficheRésultats], ao qual são passados dois parâmetros:
- o texto a ser inserido no rótulo [lblSelect]
- o [DataView] a ser vinculado ao [DataGrid1]
Este exemplo nos mostra a grande flexibilidade do componente [DataGrid]. Ele é capaz de reconhecer a estrutura do [DataView] ao qual está vinculado e se adaptar a ela. Por fim, o procedimento [btnExécuter_Click] armazena o [DataView] que acabou de obter na sessão do usuário, a fim de disponibilizá-lo quando este solicitar outras páginas do mesmo [DataView].
O procedimento [DataGrid1_PageIndexChanged] é executado quando o usuário utiliza os links [Suivant] e [Précédent] do [DataGrid]. Ele recebe dois parâmetros:
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.) Handles DataGrid1.PageIndexChanged
o objeto de origem do evento — neste caso, um dos links [Suivant] ou [Précédent] | |
informações sobre o evento. O atributo e.NewPageIndex é o número da página a ser exibida para atender à solicitação do cliente |
O código completo do gerenciador de eventos é o seguinte:
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
' mudança de página
With DataGrid1
.CurrentPageIndex = e.NewPageIndex
.DataSource = CType(Session("données"), DataView)
.DataBind()
End With
End Sub
O componente [DataGrid] possui um atributo [CurrentPageIndex] que indica o número da página que ele exibe ou irá exibir. Atribui-se a esse atributo o valor [NewPageIndex] do parâmetro [e]. O [DataGrid] é então associado ao [DataView], que havia sido armazenado na sessão, por meio do procedimento [btnExécuter_Click].
Pode-se questionar se o [DataGrid] precisa do atributo [EnableViewState=true], uma vez que seu conteúdo é calculado pelo código a cada nova execução da página. Seria de se esperar que não. No entanto, se o [DataGrid] tiver o atributo [EnableViewState=false], verifica-se que o evento [DataGrid1.PageIndexChanged] nunca é acionado. É por isso que mantivemos o [EnableViewState=true]. Sabemos que isso faz com que o conteúdo do [DataGrid] seja inserido no campo oculto [__VIEWSTATE] da página. Isso pode causar uma sobrecarga significativa na página se o [DataGrid] for grande. Se isso for um problema, é possível gerenciar a paginação manualmente, sem usar a paginação automática do [DataGrid].
O procedimento [DataGrid1_SortCommand] é executado quando o usuário clica no título de uma das colunas exibidas pelo [DataGrid] para solicitar a ordenação dos dados de acordo com essa coluna. Ele recebe dois parâmetros:
Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
o objeto de origem do evento — neste caso, um dos links [Suivant] ou [Précédent] | |
informações sobre o evento. O atributo [e.SortExpression] é o nome da coluna clicada para a ordenação |
O código completo do gerenciador de eventos é o seguinte:
Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
' classificação da visualização de dados
Dim données As DataView = CType(Session("données"), DataView)
données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
' exibindo
With DataGrid1
.CurrentPageIndex = 0
.DataSource = données
.DataBind()
End With
End Sub
Recupera-se o [DataView] visualizado pelo [DataGrid] na sessão atual. Foi o procedimento [btnExécuter_Click] que o inseriu ali. O componente [DataView] possui uma propriedade [Sort] à qual se atribui a expressão de ordenação. Essa expressão segue a sintaxe [select ... order by expr1, expr2, ...], em que cada [expri] pode ser seguido pela palavra-chave [asc] para uma ordenação crescente ou [desc] para uma ordenação decrescente. A expressão [order by] utilizada aqui é [order by colonne asc/desc]. A propriedade [e.SortExpression] nos fornece o nome da coluna do [DataGrid] que foi selecionada para a ordenação. A sequência [asc/desc] é definida com base nos valores dos botões de opção do grupo [rdTri]. Uma vez definida a expressão de classificação do [DataView], o [DataGrid] é associado a ela. O [DataGrid] é posicionado em sua primeira página.
8.7. Componente DataList e ligação de dados
Passamos agora a analisar o componente [DataList]. Ele oferece mais possibilidades de formatação do que o [DataGrid], mas é menos flexível. Assim, ele não consegue se adaptar automaticamente à fonte de dados à qual está vinculado. É necessário fazer essa adaptação por meio de código, caso seja desejada. Se a estrutura da fonte de dados for conhecida de antemão, esse componente oferece opções de formatação que podem torná-lo preferível ao [DataGrid].
8.7.1. Aplicação
Para ilustrar o uso do [DataList], criamos uma aplicação MVC análoga à anterior:
![]() |
As três visualizações serão incorporadas ao código de apresentação do controlador [main.aspx] na forma de contêineres. Portanto, essa aplicação possui uma única página [main.aspx].
8.7.2. As classes de negócio
A classe [produits] é a mesma da anterior.
8.7.3. As visualizações
Quando o usuário faz sua primeira solicitação ao aplicativo, ele obtém a seguinte visualização [résultats1]:
![]() |
n.º | nome | tipo | propriedades | função |
1 | RadioButton | EnableViewState=false | permite escolher um dos dois estilos de [DataList] | |
2 | Botão | EnableViewState=false | botão [submit] | |
3 | DataList | EnableViewState=true | campo de exibição da lista de dados |
Se o usuário escolher o estilo nº 2, ele obterá a seguinte visualização [résultats2]:
![]() |
n.º | nome | tipo | propriedades | função |
1 | DataList | EnableViewState=true | campo de exibição da lista de dados |
A visualização [erreurs] indica um problema de acesso à fonte de dados:
![]() |
n.º | nome | tipo | propriedades | função |
1 | variável | código HTML necessário para a exibição de erros |
As três visualizações do aplicativo são três contêineres (painéis) diferentes dentro da mesma página [main.aspx]. Seu código de apresentação é o seguinte:
<%@ Page src="main.aspx.vb" inherits="main" autoeventwireup="false" Language="vb" %>
<HTML>
<HEAD>
</HEAD>
<body>
<P>Liaison de données avec un DataList</P>
<HR width="100%" SIZE="1">
<form runat="server" ID="Form1">
<asp:Panel Runat="server" ID="bandeau">
<P>Choisissez votre style :
<asp:RadioButton id="RadioButton1" runat="server" EnableViewState="False" Text="1" GroupName="rdstyle"
Checked="True"></asp:RadioButton>
<asp:RadioButton id="RadioButton2" runat="server" EnableViewState="False" Text="2" GroupName="rdstyle"></asp:RadioButton>
<asp:Button id="btnChanger" runat="server" EnableViewState="False" Text="Changer"></asp:Button></P>
<HR width="100%" SIZE="1">
</asp:Panel>
<asp:Panel id="vueRésultats1" runat="server">
<P>
<asp:DataList id="DataList1" runat="server" BorderColor="Tan" BorderWidth="1px" BackColor="LightGoldenrodYellow"
CellPadding="2" RepeatDirection="Horizontal" RepeatColumns="4" ForeColor="Black">
<SelectedItemStyle ForeColor="GhostWhite" BackColor="DarkSlateBlue"></SelectedItemStyle>
<HeaderTemplate>
Contenu de la table [liste] de la base [produits]
</HeaderTemplate>
<AlternatingItemStyle BackColor="PaleGoldenrod"></AlternatingItemStyle>
<ItemTemplate>
nom :
<%# Container.DataItem("nome") %>
<br>
prix :
<%# databinder.eval(Container.DataItem,"preço","{0:C}") %>
<br>
</ItemTemplate>
<FooterStyle BackColor="Tan"></FooterStyle>
<HeaderStyle Font-Bold="True" BackColor="Tan"></HeaderStyle>
</asp:DataList></P>
</asp:Panel>
<asp:Panel id="vueRésultats2" runat="server">
<P>
<asp:DataList id="DataList2" runat="server">
<HeaderTemplate>
Contenu de la table [liste] de la base [produits]
<HR width="100%" SIZE="1">
</HeaderTemplate>
<AlternatingItemStyle BackColor="Teal"></AlternatingItemStyle>
<SeparatorStyle BackColor="LightSkyBlue"></SeparatorStyle>
<ItemStyle BackColor="#C0C000"></ItemStyle>
<ItemTemplate>
nom :
<%# Container.DataItem("nome") %>
, prix :
<%# databinder.eval(Container.DataItem,"preço","{0:C}") %>
<BR>
</ItemTemplate>
<SeparatorTemplate>
<HR width="100%" SIZE="1">
</SeparatorTemplate>
<HeaderStyle BackColor="#C0C0FF"></HeaderStyle>
</asp:DataList></P>
</asp:Panel>
<asp:Panel id="vueErreurs" runat="server">
<P>Les erreurs suivantes se sont produites :</P>
<%= erreursHTML %>
</asp:Panel>
</form>
</body>
</HTML>
8.7.4. Configuração dos componentes [DataList]
Vamos examinar os diferentes atributos de um componente [DataList]. São muitos, e apresentaremos apenas uma pequena parte deles. É possível definir até sete modelos de exibição dentro de um [DataList]:
modelo do cabeçalho do [DataList] | |
modelo das linhas que exibem os elementos da lista de dados associada. Apenas este modelo é obrigatório. | |
Para diferenciar visualmente os elementos sucessivos exibidos, podem ser utilizados dois modelos: ItemTemplate para o elemento n e AlternatingItemTemplate para o elemento n+1 | |
modelo do elemento selecionado no [DataList] | |
modelo do separador entre dois elementos do [DataList] | |
um [DataList] permite a modificação dos valores que exibe. [EditItemTemplate] é o modelo de um elemento do [DataList] para o qual se está no modo “edição” | |
modelo do rodapé do [DataList] |
O componente [DataList1] foi criado com base no [WebMatrix]. Na janela de propriedades, foi selecionado o link [Mise en forme automatique]:
![]() | 1234567 ![]() |
Acima, o esquema [Couleur 5] irá gerar um [DataList] com estilos para os seguintes modelos: HeaderTemplate (1), ItemTemplate (2, 6), AlternatingTemplate (3, 5), SelectedItemTemplate (4), FooterTemplate (7). O código gerado é o seguinte:
<asp:DataList id="DataList1" runat="server" BorderColor="Tan" BorderWidth="1px" BackColor="LightGoldenrodYellow"
CellPadding="2" ForeColor="Black">
<SelectedItemStyle ForeColor="GhostWhite" BackColor="DarkSlateBlue"></SelectedItemStyle>
<AlternatingItemStyle BackColor="PaleGoldenrod"></AlternatingItemStyle>
<FooterStyle BackColor="Tan"></FooterStyle>
<HeaderStyle Font-Bold="True" BackColor="Tan"></HeaderStyle>
</asp:DataList></P>
Nenhum modelo foi definido. Cabe a nós fazê-lo. Definimos os seguintes modelos:
| |
|
Vale lembrar que o modelo [ItemTemplate] é responsável pela exibição dos elementos da fonte de dados vinculada ao [DataList]. Essa fonte de dados é um conjunto de linhas de dados, cada uma contendo um ou mais valores. A linha atual da fonte de dados é representada pelo objeto [Container.DataItem]. Essa linha possui colunas. [Container.DataItem("col1")] é o valor da coluna “col1” da linha atual. Para incluir esse valor no código de apresentação, escreve-se <%# Container.DataItem("col") %>. Às vezes, deseja-se apresentar um elemento da linha atual em um formato especial. Neste caso, queremos exibir a coluna “preço” da linha atual em euros. Para isso, utilizamos a função [DataBinder.Eval], que aceita três parâmetros:
- a linha atual [Container.DataItem]
- o nome da coluna a ser formatada
- a string de formatação no formato {0:formato}, em que [format] é um dos formatos aceitos pelo método [string.format].
Assim, o código <%# DataBinder.Eval(Container.DataItem,"preço",{0:C}) %> fará com que a coluna [prix] da linha atual seja exibida no formato monetário (formato C = Moeda).
Teremos, portanto, um [DataList] que ficará assim:

Acima, os dados foram dispostos à razão de quatro dados por linha. Isso é obtido com os seguintes atributos de [DataList]:
Horizontal | |
número de colunas desejado |
No final, o código de [DataList1] é aquele que foi apresentado no código de apresentação um pouco acima. Deixamos a cargo do leitor a tarefa de estudar o código de apresentação de [DataList2]. Assim como no componente [DataGrid], a maioria das propriedades do [DataList] pode ser definida por meio de um assistente do [WebMatrix]. Para isso, utiliza-se o link [Générateur de propriétés] na janela de propriedades do [DataList]:
![]() | ![]() |
8.7.5. Os controladores
O controlador [global.asax, global.asax.vb] é o seguinte:
[global.asax]
[global.asax.vb]
Imports System
Imports System.Web
Imports System.Web.SessionState
Imports st.istia.univangers.fr
Imports System.Configuration
Imports System.Data
Imports System.Collections
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' criamos um objeto “produtos”
Try
Dim données As DataSet = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection")).getDataSet("select * from LISTE")
' insere-se o objeto no aplicativo
Application("données") = données
' sem erros
Application("erreur") = False
Catch ex As Exception
'ocorreu um erro, que é registrado no aplicativo
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
End Class
Quando o aplicativo é iniciado (Application_Start), criamos um [dataset] a partir da classe de negócios [produits] e o inserimos no aplicativo para que esteja disponível para todas as solicitações de todos os clientes. Se ocorrer uma exceção durante essa criação, ela será registrada na aplicação. O procedimento [Application_Start] será executado apenas uma vez. A partir daí, o controlador [global.asax] não será mais acionado. Será o controlador [main.aspx.vb] que assumirá a tarefa:
Imports System.Collections
Imports Microsoft.VisualBasic
Imports System.Data
Imports st.istia.univangers.fr
Imports System
Imports System.Xml
Public Class main
Inherits System.Web.UI.Page
' componentes da página
Protected WithEvents vueErreurs As System.Web.UI.WebControls.Panel
Protected WithEvents DataList1 As System.Web.UI.WebControls.DataList
Protected WithEvents DataList2 As System.Web.UI.WebControls.DataList
Protected WithEvents vueRésultats1 As System.Web.UI.WebControls.Panel
Protected WithEvents vueRésultats2 As System.Web.UI.WebControls.Panel
Protected WithEvents RadioButton1 As System.Web.UI.WebControls.RadioButton
Protected WithEvents RadioButton2 As System.Web.UI.WebControls.RadioButton
Protected WithEvents btnChanger As System.Web.UI.WebControls.Button
Protected WithEvents bandeau As System.Web.UI.WebControls.Panel
' dados da página
Protected erreursHTML As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' verifica-se se o aplicativo está com erro
If CType(Application("erreur"), Boolean) Then
' o aplicativo não foi inicializado corretamente
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs, False)
Exit Sub
End If
'1ª solicitação
If Not IsPostBack Then
' inicializamos os controles
With DataList1
.DataSource = CType(Application("données"), DataSet)
.DataBind()
End With
With DataList2
.DataSource = CType(Application("données"), DataSet)
.DataBind()
End With
' exibe o formulário vazio
afficheRésultats(True, False)
End If
End Sub
Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
' exibe a visualização de erros
erreursHTML = ""
For i As Integer = 0 To erreurs.Count - 1
erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
Next
' exibindo a visualização [erreurs]
vueErreurs.Visible = True
vueRésultats1.Visible = False
vueRésultats2.Visible = False
bandeau.Visible = False
End Sub
Private Sub afficheRésultats(ByVal visible1 As Boolean, ByVal visible2 As Boolean)
' exibe a visualização [résultats]
vueRésultats1.Visible = visible1
vueRésultats2.Visible = visible2
vueErreurs.Visible = False
End Sub
Private Sub btnChanger_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnChanger.Click
' altera o estilo
afficheRésultats(RadioButton1.Checked, RadioButton2.Checked)
End Sub
End Class
8.8. Componente Repeater e ligação de dados
O componente [Repeater] permite repetir o código HTML de cada um dos elementos de uma lista de dados. Suponhamos que se queira exibir uma lista de erros no seguinte formato:

Já nos deparamos com esse problema e o resolvemos inserindo no código de apresentação uma variável no formato <ul><% =erreursHTML %></ul>, sendo que o valor de erreursHTML é calculado pelo controlador. Esse valor contém o código HTML, que corresponde a uma lista. Isso apresenta a desvantagem de que, se quisermos modificar a apresentação dessa lista HTML, somos obrigados a acessar a parte do controlador, o que vai contra a separação entre controlador e apresentação. O componente [Repeater] nos oferece uma solução. Assim como no [DataList], é possível definir os modelos <HeaderTemplate> para o cabeçalho, <ItemTemplate> para o item atual da lista de dados e <FooterTemplate> para o final dos dados. Aqui, poderíamos ter a seguinte definição para o componente [Repeater]:
<asp:Repeater id="Repeater1" runat="server" EnableViewState="False">
<HeaderTemplate>
Les erreurs suivantes se sont produites :
<ul>
</HeaderTemplate>
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
Vale lembrar que [Container.DataItem] representa uma linha de dados se a fonte de dados tiver várias colunas. Representa um dado se a fonte tiver apenas uma coluna. Esse será o caso aqui. A título de exemplo, vamos criar o seguinte aplicativo:

O código de apresentação da página é o seguinte:
<html>
<head>
</head>
<body>
<form runat="server">
<p>
Liaison de données avec un composant [Repeater]
</p>
<hr />
<p>
<asp:Repeater id="Repeater1" runat="server" EnableViewState="False">
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
<HeaderTemplate>
Les erreurs suivantes se sont produites :
<ul>
</HeaderTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</p>
</form>
</body>
</html>
O código de controle é o seguinte:
<%@ Page Language="VB" %>
<script runat="server">
' procedimento executado ao carregar a página
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' é criada uma fonte de dados
with Repeater1
.DataSource=createDataSource
.DataBind
end with
end if
End Sub
function createDataSource as ArrayList
' cria uma arraylist
dim erreurs as new ArrayList
dim i as integer
for i=0 to 5
erreurs.add("erreur-"+i.ToString)
next
return erreurs
end function
</script>
<html>
...
</html>
À primeira solicitação do cliente, associamos um objeto [ArrayList] ao componente [Repeater], que supostamente representa uma lista de erros.
8.9. Application
Retomamos aqui uma aplicação já tratada com componentes de servidor. A aplicação permite realizar simulações de cálculos de impostos. Ela se baseia em uma classe [impot], que não será abordada aqui. Essa classe necessita de dados que encontra em uma fonte de dados OLEDB. Para o exemplo, será uma fonte ACCESS. Trazemos as seguintes novidades nesta nova versão:
- o uso de componentes de validação para verificar a validade dos dados
- o uso de componentes de servidor vinculados a fontes de dados para a exibição dos resultados
8.9.1. A estrutura MVC do aplicativo
A estrutura MVC do aplicativo é a seguinte:
![]() |
As três visualizações serão incorporadas ao código de apresentação do controlador [main.aspx] na forma de contêineres. Portanto, essa aplicação possui uma única página, [main.aspx].
8.9.2. As visualizações da aplicação
A visualização [formulaire] é o formulário de preenchimento de informações que permite o cálculo do imposto de um usuário:

O usuário preenche o formulário:

Ele utiliza o botão [Envoyer] para solicitar o cálculo do seu imposto. Ele obtém a seguinte visualização [simulations]:

Ele retorna ao formulário pelo link acima. Ele o encontra exatamente como o preencheu. Ele pode cometer erros de preenchimento:

Esses erros são sinalizados na tela [formulaire]:

O usuário corrige então seus erros. Ele pode realizar novas simulações:

Ele obtém então a tela [simulations] com mais uma simulação:

Por fim, se a fonte de dados não estiver disponível, isso é sinalizado ao usuário na visualização [erreurs]:

8.9.2.1. O código de apresentação
Vale lembrar que a página [main.aspx] reúne todas as visualizações. Trata-se de um único formulário com três contêineres:
- [panelform] para a visualização [formulaire]
- [panelerreurs] para a visualização [erreurs]
- [panelsimulations] para a visualização [simulations]
Apresentamos agora os detalhes dos componentes desses três contêineres. O contêiner [panelform] tem a seguinte representação visual:
![]() |
n.º | nome | tipo | propriedades | função |
Painel | visualização do formulário | |||
RadioButton | GroupName=rdmarie | botões de opção | ||
CustomValidator | ErrorMessage=Você não informou seu estado civil EnableClientScript=false | verifica se o programa cliente enviou o estado civil esperado | ||
TextBox | número de filhos | |||
RequiredFieldValidator | ErrorMessage=Informe o número de filhos ControlToValidate=txtEnfants | verifica se o campo [txtEnfants] não está vazio | ||
RangeValidator | ErrorMessage=Digite um número entre 1 e 30 ControlToValidate=txtEnfants | verifica se o campo [txtEnfants] está dentro do intervalo [1,30] | ||
TextBox | EnableViewState=true | salário anual | ||
RequiredFieldValidator | ControlToValidate=txtSalário ErrorMessage=Informe o valor do seu salário | verifica se o campo [txtSalaire] não está vazio | ||
RegularExpressionValidator | ControlToValidate=txtSalário ErrorMessage=Salário inválido ExpressãoRegular=\s*\d+\s* | verifica se o campo [txtSalaire] é uma sequência de algarismos | ||
Botão | CausesValidation=true | botão [submit] do formulário — inicia o cálculo do imposto | ||
Botão | CausesValidation=false | botão [submit] do formulário — limpa o formulário |
Pode parecer surpreendente que o controle [cvMarié] seja responsável por verificar se o usuário realmente marcou um dos dois botões de opção. Na verdade, não poderia ser de outra forma se ele estiver utilizando corretamente o formulário enviado pelo servidor. Como não há como garantir isso, somos obrigados a verificar todos os parâmetros enviados. Observe-se também o atributo [CausesValidation=false] do botão [btnEffacer]. De fato, quando o usuário utiliza esse botão, não se deve verificar os dados enviados, uma vez que eles serão ignorados.
Todos os componentes do contêiner possuem a propriedade [EnableViewState=false], exceto [panelForm, txtEnfants, txtSalaire, rdOui, rdNon]. O contêiner [panelerreurs] tem a seguinte representação visual:
![]() |
n.º | nome | tipo | propriedades | função |
Painel | EnableViewState=false | visualização de erros | ||
Repetidor | EnableViewState=false | exibe uma lista de erros |
O componente [rptErreurs] está definido da seguinte forma:
<asp:Repeater id="rptErreurs" runat="server" EnableViewState="False">
<ItemTemplate>
<li>
<%# Container.Dataitem%>
</li>
</ItemTemplate>
<HeaderTemplate>
Les erreurs suivantes se sont produites
<ul>
</HeaderTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
A lista de dados associada ao componente [rptErreurs] será um objeto [ArrayList] contendo uma lista de mensagens de erro. Assim, no exemplo acima, <%# Container.Dataitem%> designa a mensagem de erro atual. O contêiner [panelsimulations] tem a seguinte representação visual:
![]() |
n.º | nome | tipo | propriedades | função |
Painel | EnableViewState=false | visualização de simulações | ||
LinkButton | EnableViewState=false | link para o formulário | ||
DataGrid | EnableViewState=false | responsável por exibir as simulações inseridas em um objeto [DataTable] |
O componente [dgSimulations] está configurado da seguinte maneira em [Webmatrix]. Na janela de propriedades do [dgSimulations], selecionamos o link [Mise en forme automatique] e selecionamos o esquema [Couleur 3]:
![]() | ![]() |
Em seguida, ainda na janela de propriedades de [dlgSimulations], selecionamos o link [Générateur de propriétés]. Solicitamos a exibição dos cabeçalhos das colunas:

Selecionamos a opção [Colonnes] para definir as quatro colunas do [DataGrid]:

Desmarcamos a frase [Créer des colonnes automatiquement ...]. Vamos definir nós mesmos as quatro colunas do [DataGrid]. Este será associado a um objeto [DataTable] com quatro colunas denominadas, respectivamente, “casado”, “filhos”, “salário” e “imposto”. Para criar uma coluna no [DataGrid], selecionamos a opção [Colonnes connexe] e utilizamos o botão de criação, conforme indicado acima. Uma coluna é criada e podemos definir suas características. A primeira coluna da tabela de simulações conterá a coluna “casado” do objeto [DataTable], que será associado ao [DataGrid]. Essa primeira coluna do [DataGrid] é definida da seguinte forma no assistente:

título da coluna, neste caso “Casado” | |
nome da coluna da fonte de dados que será exibida por esta coluna do [DataGrid]. Aqui, trata-se da coluna “casado” do [DataTable]. |
A segunda coluna é definida da seguinte forma:
Filhos | |
filhos |
A terceira coluna é definida da seguinte forma:
Salário anual | |
salário | |
{0:C} - formatação monetária para exibir o símbolo do euro |
A quarta coluna é definida da seguinte forma:
Valor do imposto | |
imposto | |
{0:C} - formatação monetária para exibir o símbolo do euro |
Colocamos o código de apresentação e o código de controle em dois arquivos separados. O primeiro estará em [main.aspx] e o segundo em [main.aspx.vb]. O código de [main.aspx] é o seguinte:
<%@ page src="main.aspx.vb" inherits="main" AutoEventWireUp="false" %>
<HTML>
<HEAD>
<title>Calculer votre impôt</title>
</HEAD>
<body>
<P>Calculer votre impôt</P>
<HR width="100%" SIZE="1">
<FORM id="Form1" runat="server">
<asp:panel id="panelform" Runat="server">
<TABLE id="Table1" cellSpacing="1" cellPadding="1" border="0">
<TR>
<TD height="19">Etes-vous marié(e)</TD>
<TD height="19">
<asp:RadioButton id="rdOui" runat="server" GroupName="rdMarie"></asp:RadioButton>Oui
<asp:RadioButton id="rdNon" runat="server" GroupName="rdMarie" Checked="True"></asp:RadioButton>Non
<asp:CustomValidator id="cvMarie" runat="server" ErrorMessage="Vous n'avez pas indiqué votre état marital"
Display="Dynamic" EnableClientScript="False" Visible="False" EnableViewState="False"></asp:CustomValidator></TD>
</TR>
<TR>
<TD>Nombre d'enfants</TD>
<TD>
<asp:TextBox id="txtEnfants" runat="server" Columns="3" MaxLength="3"></asp:TextBox>
<asp:RequiredFieldValidator id="rfvEnfants" runat="server" ErrorMessage="Indiquez le nombre d'enfants" Display="Dynamic"
ControlToValidate="txtEnfants" EnableViewState="False"></asp:RequiredFieldValidator>
<asp:RangeValidator id="rvEnfants" runat="server" ErrorMessage="Tapez un nombre entre 1 et 30" Display="Dynamic"
ControlToValidate="txtEnfants" Type="Integer" MaximumValue="30" MinimumValue="0" EnableViewState="False"></asp:RangeValidator></TD>
</TR>
<TR>
<TD>Salaire annuel (euro)</TD>
<TD>
<asp:TextBox id="txtSalaire" runat="server" Columns="10" MaxLength="10"></asp:TextBox>
<asp:RequiredFieldValidator id="rfvSalaire" runat="server" ErrorMessage="Indiquez le montant de votre salaire"
Display="Dynamic" ControlToValidate="txtSalaire" EnableViewState="False"></asp:RequiredFieldValidator>
<asp:RegularExpressionValidator id="revSalaire" runat="server" ErrorMessage="Salaire invalide" Display="Dynamic"
ControlToValidate="txtSalaire" ValidationExpression="\s*\d+\s*" EnableViewState="False"></asp:RegularExpressionValidator></TD>
</TR>
</TABLE>
<P>
<asp:Button id="btnCalculer" runat="server" Text="Calculer"></asp:Button>
<asp:Button id="btnEffacer" runat="server" Text="Effacer" CausesValidation="False"></asp:Button></P>
</asp:panel>
<asp:panel id="panelerreurs" runat="server" EnableViewState="False">
<asp:Repeater id="rptErreurs" runat="server" EnableViewState="False">
<ItemTemplate>
<li>
<%# Container.Dataitem%>
</li>
</ItemTemplate>
<HeaderTemplate>
Les erreurs suivantes se sont produites
<ul>
</HeaderTemplate>
<FooterTemplate>
</ul>
</FooterTemplate>
</asp:Repeater>
</asp:panel>
<asp:panel id="panelsimulations" runat="server" EnableViewState="False">
<P>
<asp:DataGrid id="dgSimulations" runat="server" BorderColor="#DEBA84" BorderStyle="None" CellSpacing="2"
BorderWidth="1px" BackColor="#DEBA84" CellPadding="3" AutoGenerateColumns="False" EnableViewState="False">
<SelectedItemStyle Font-Bold="True" ForeColor="White" BackColor="#738A9C"></SelectedItemStyle>
<ItemStyle ForeColor="#8C4510" BackColor="#FFF7E7"></ItemStyle>
<HeaderStyle Font-Bold="True" ForeColor="White" BackColor="#A55129"></HeaderStyle>
<FooterStyle ForeColor="#8C4510" BackColor="#F7DFB5"></FooterStyle>
<Columns>
<asp:BoundColumn DataField="marié" HeaderText="Marié"></asp:BoundColumn>
<asp:BoundColumn DataField="enfants" HeaderText="Enfants"></asp:BoundColumn>
<asp:BoundColumn DataField="salaire" HeaderText="Salaire annuel" DataFormatString="{0:C}"></asp:BoundColumn>
<asp:BoundColumn DataField="impôt" HeaderText="Montant de l'impôt" DataFormatString="{0:C}"></asp:BoundColumn>
</Columns>
<PagerStyle HorizontalAlign="Center" ForeColor="#8C4510" Mode="NumericPages"></PagerStyle>
</asp:DataGrid></P>
<P>
<asp:LinkButton id="lnkForm2" runat="server" EnableViewState="False">Retour au formulaire</asp:LinkButton></P>
</asp:panel>
</FORM>
</body>
</HTML>
8.9.3. O código de controle do aplicativo
O código de controle do aplicativo está distribuído nos arquivos [global.asax.vb] e [main.aspx.vb]. O arquivo [global.asax] está definido da seguinte forma:
O arquivo [global.asax.vb] é o seguinte:
Imports System
Imports System.Web
Imports System.Web.SessionState
Imports st.istia.univangers.fr
Imports System.Configuration
Imports System.Collections
Imports System.Data
Public Class Global
Inherits System.Web.HttpApplication
Sub Application_Start(ByVal sender As Object, ByVal e As EventArgs)
' cria-se um objeto `impot`
Dim objImpot As impot
Try
objImpot = New impot(New impotsOLEDB(ConfigurationSettings.AppSettings("chaineConnexion")))
' coloca-se o objeto no aplicativo
Application("objImpot") = objImpot
' sem erros
Application("erreur") = False
Catch ex As Exception
'ocorreu um erro; registra-se isso no aplicativo
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
' início da sessão — cria-se uma lista de simulações vazia
Dim simulations As New DataTable("simulations")
simulations.Columns.Add("marié", Type.GetType("System.String"))
simulations.Columns.Add("enfants", Type.GetType("System.String"))
simulations.Columns.Add("salaire", Type.GetType("System.Int32"))
simulations.Columns.Add("impôt", Type.GetType("System.Int32"))
Session.Item("simulations") = simulations
End Sub
End Class
Quando o aplicativo é iniciado (primeira solicitação feita ao aplicativo), o procedimento [Application_Start] é executado. Ele procura criar um objeto do tipo [impot], obtendo seus dados de uma fonte OLEDB. Recomenda-se ao leitor que consulte o capítulo 5, onde essa classe foi definida, caso tenha esquecido. A criação do objeto [impot] pode falhar se a fonte de dados não estiver disponível. Nesse caso, o erro é armazenado na aplicação para que todas as consultas posteriores saibam que ela não pôde ser inicializada corretamente. Se a criação ocorrer sem problemas, o objeto [impot] criado também é armazenado na aplicação. Ele será utilizado por todas as consultas de cálculo de imposto. Quando um cliente faz sua primeira consulta, uma sessão é criada para ele pelo procedimento [Application_Start]. Essa sessão destina-se a armazenar as diferentes simulações de cálculo de imposto que ele realizará. Elas serão armazenadas em um objeto [DataTable] associado à chave de sessão “simulações”. Quando a sessão é iniciada, essa chave é associada a um objeto [DataTable] vazio, mas cuja estrutura já foi definida. As informações necessárias para a aplicação são colocadas em seu arquivo de configuração [wenConfig]:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<appSettings>
<add key="chaineConnexion" value="Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=D:\data\devel\aspnet\poly\webforms2\vs\impots6\impots.mdb" />
</appSettings>
</configuration>
A chave [chaineConnexion] identifica a cadeia de conexão com a fonte OLEDB. A outra parte do código de controle está em [main.aspx.vb]:
Imports System.Collections
Imports Microsoft.VisualBasic
Imports st.istia.univangers.fr
Imports System
Imports System.Web.UI.Control
Imports System.Data
Public Class main
Inherits System.Web.UI.Page
Protected WithEvents rdOui As System.Web.UI.WebControls.RadioButton
Protected WithEvents rdNon As System.Web.UI.WebControls.RadioButton
Protected WithEvents txtEnfants As System.Web.UI.WebControls.TextBox
Protected WithEvents txtSalaire As System.Web.UI.WebControls.TextBox
Protected WithEvents btnCalculer As System.Web.UI.WebControls.Button
Protected WithEvents btnEffacer As System.Web.UI.WebControls.Button
Protected WithEvents panelform As System.Web.UI.WebControls.Panel
Protected WithEvents lnkForm2 As System.Web.UI.WebControls.LinkButton
Protected WithEvents panelerreurs As System.Web.UI.WebControls.Panel
Protected WithEvents rfvEnfants As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents rvEnfants As System.Web.UI.WebControls.RangeValidator
Protected WithEvents rfvSalaire As System.Web.UI.WebControls.RequiredFieldValidator
Protected WithEvents rptErreurs As System.Web.UI.WebControls.Repeater
Protected WithEvents dgSimulations As System.Web.UI.WebControls.DataGrid
Protected WithEvents revSalaire As System.Web.UI.WebControls.RegularExpressionValidator
Protected WithEvents cvMarie As System.Web.UI.WebControls.CustomValidator
Protected WithEvents panelsimulations As System.Web.UI.WebControls.Panel
' variáveis locais
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
...
End Sub
Private Sub afficheErreurs(ByRef erreurs As ArrayList)
...
End Sub
Private Sub afficheFormulaire()
...
End Sub
Private Sub afficheSimulations(ByRef simulations As DataTable, ByRef lien As String)
...
End Sub
Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
....
End Sub
Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs)
...
End Sub
Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
...
End Sub
Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
...
End Sub
Private Sub razForm()
...
End Sub
Private Sub cvMarie_ServerValidate(ByVal source As System.Object, ByVal args As System.Web.UI.WebControls.ServerValidateEventArgs)
...
End Sub
End Class
O primeiro evento processado pelo código é [Page_Load]:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' primeiro, verifica-se o estado do aplicativo
If CType(Application("erreur"), Boolean) Then
' o aplicativo não conseguiu ser inicializado
' exibe-se a tela de erros
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs)
Exit Sub
End If
' sem erros — na primeira solicitação, exibimos o formulário
If Not IsPostBack Then afficheFormulaire()
End Sub
Antes de iniciar o processamento da solicitação, verificamos se o aplicativo foi inicializado corretamente. Caso contrário, exibimos a visualização [erreurs] por meio do procedimento [afficheErreurs]. Se for a primeira solicitação (IsPostBack=false), exibimos a visão [formulaire] com [afficheFormulaire].
O procedimento que exibe a visualização [erreurs] é o seguinte:
Private Sub afficheErreurs(ByRef erreurs As ArrayList)
' cria a lista de erros
With rptErreurs
.DataSource = erreurs
.DataBind()
End With
' exibição dos contêineres
panelerreurs.Visible = True
panelform.Visible = False
panelsimulations.Visible = False
Exit Sub
End Sub
O procedimento recebe como parâmetro uma lista de mensagens de erro no [erreurs] do tipo [ArrayList]. Basta vincular essa fonte de dados ao componente [rptErreurs], responsável por exibi-la.
O procedimento que exibe a visualização [formulaire] é o seguinte:
Private Sub afficheFormulaire()
' exibe o formulário
panelform.Visible = True
' os demais contêineres ficam ocultos
panelerreurs.Visible = False
panelsimulations.Visible = False
End Sub
Este procedimento limita-se a tornar visível o contêiner [panelform]. Os componentes são exibidos com seu valor lançado ou anterior (VIEWSTATE).
Quando o usuário clica no botão [Calculer] da visualização [formulaire], é realizada uma transição de POST para [main.aspx]. O procedimento [Page_Load] é executado e, em seguida, o procedimento [btnCalculer_Click]:
Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
' verifica-se a validade dos dados inseridos; se houver erros, eles são sinalizados
If Not Page.IsValid Then
afficheFormulaire()
Exit Sub
End If
' sem erros — calcula-se o imposto
Dim impot As Long = CType(Application("objImpot"), impot).calculer( _
rdOui.Checked, CType(txtEnfants.Text, Integer), CType(txtSalaire.Text, Long))
' o resultado é adicionado às simulações existentes
Dim simulations As DataTable = CType(Session.Item("simulations"), DataTable)
Dim simulation As DataRow = simulations.NewRow
simulation("marié") = CType(IIf(rdOui.Checked, "oui", "non"), String)
simulation("enfants") = txtEnfants.Text.Trim
simulation("salaire") = CType(txtSalaire.Text.Trim, Long)
simulation("impôt") = impot
simulations.Rows.Add(simulation)
' as simulações são inseridas na sessão
Session.Item("simulations") = simulations
' exibe-se a página das simulações
afficheSimulations(simulations, "Retour au formulaire")
End Sub
O procedimento começa verificando a validade da página. Vale lembrar que, quando o procedimento [btnCalculer_Click] é executado, as verificações de validação já foram realizadas e o atributo [IsValid] da página foi definido. Se a página não for válida, a visualização [formulaire] é exibida novamente e o procedimento é encerrado. Os componentes de validação da visualização [formulaire] cujos atributos variam de [IsValid] a [false] exibirão seu atributo [ErrorMessage]. Se a página for válida, o valor do imposto é calculado por meio do objeto do tipo [impot], que havia sido armazenado no aplicativo no momento de sua inicialização. Essa nova simulação é adicionada à lista de simulações já realizadas e armazenada na sessão.
Por fim, a visualização [simulations] é exibida pelo procedimento [afficheSimulations] a seguir:
Private Sub afficheSimulations(ByRef simulations As DataTable, ByRef lien As String)
' vincula-se a grade de dados à fonte “simulações”
With dgSimulations
.DataSource = simulations
.DataBind()
End With
' vínculo
lnkForm2.Text = lien
' as visualizações
panelsimulations.Visible = True
panelerreurs.Visible = False
panelform.Visible = False
End Sub
O procedimento possui dois parâmetros:
- uma lista de simulações em [simulations] do tipo [DataTable]
- um texto de link em [lien]
A fonte de dados [simulations] está vinculada ao componente responsável por exibi-la. O texto do link, por sua vez, está definido na propriedade [Text] do objeto [LinkButton] da visualização.
Quando o usuário clica no botão [Effacer] da visualização [formulaire], é executado o procedimento [btnEffacer_click] (sempre após o [Page_Load]):
Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
' exibe o formulário vazio
razForm()
afficheFormulaire()
End Sub
Private Sub razForm()
' esvazia o formulário
rdOui.Checked = False
rdNon.Checked = True
txtEnfants.Text = ""
txtSalaire.Text = ""
End Sub
O código acima é simples o suficiente para não precisar de comentários. Resta-nos tratar do clique nos links das visualizações [erreurs] e [simulations]:
Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm1.Click
' exibe o formulário
afficheFormulaire()
End Sub
Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
' exibe o formulário
afficheFormulaire()
End Sub
Ambos os procedimentos limitam-se a exibir a visualização [formulaire]. Sabemos que os campos dessa visualização receberão um valor que será ou o valor lançado para eles ou seu valor anterior. Como, neste caso, o POST do cliente não envia nenhum valor para os campos do formulário, estes recuperarão seu valor anterior. O formulário é, portanto, exibido com os valores inseridos pelo usuário.
8.9.4. Testes
Todos os arquivos necessários para a aplicação estão localizados em uma pasta <application-path>: ![]() | A pasta [bin] contém a DLL com as classes [impot], [impotsData] e [impotsOLEDB] necessárias para a aplicação: |
O leitor poderá, se desejar, reler o capítulo 5, onde é explicada a maneira de criar o arquivo [impot.dll] mencionado acima. Feito isso, o servidor Cassini é iniciado com os parâmetros (<application-path>,/impots6). Acesse a URL [http://impots6/main.aspx] com um navegador:

Se renomearmos o arquivo ACCESS [impots.mdb] para [impots1.mdb], teremos a seguinte página:

8.9.5. Conclusão
Temos um aplicativo MVC que utiliza apenas componentes de servidor. O uso desses componentes permitiu separar completamente a parte de apresentação do aplicativo da parte de controle. Isso ainda não era possível até agora, quando o código de apresentação continha variáveis calculadas pelo código de controle e cujo valor incluía código HTML. Agora, isso não acontece mais.






















