8. Componenti server ASP - 2
8.1. Introduction
Continuiamo il nostro lavoro sull’interfaccia utente scoprendo:
- componenti per la convalida dei dati
- come collegare i dati ai componenti server
- i componenti server HTML
8.2. I componenti di validazione dei dati
8.2.1. Introduzione
Nelle applicazioni basate su moduli, è fondamentale verificare la validità dei dati inseriti nei moduli stessi. Nell'esempio sul calcolo delle imposte, avevamo il seguente modulo:

Una volta ricevuti i valori di questo modulo, dobbiamo verificare la validità dei dati inseriti: il numero di figli e lo stipendio devono essere numeri interi positivi o pari a zero. In caso contrario, il modulo viene rinviato al cliente così come è stato compilato, con messaggi che indicano gli errori. Avevamo gestito questo caso con due viste, una per il modulo sopra riportato e l’altra per gli errori:

ASP.NET offre dei componenti denominati «componenti di validazione» che consentono di verificare i seguenti casi:
Componente | Ruolo |
verifica che un campo non sia vuoto | |
verifica la corrispondenza tra due valori | |
verifica che un valore rientri in un intervallo | |
verifica che un campo soddisfi un'espressione regolare | |
consente allo sviluppatore di definire le proprie regole di convalida - questo componente potrebbe sostituire tutti gli altri | |
consente di raggruppare i messaggi di errore generati dai controlli precedenti in un unico punto della pagina |
Ora presenteremo ciascuno di questi componenti.
8.2.2. RequiredFieldValidator
Creiamo la seguente pagina [requiredfieldvalidator1.aspx]:
![]() |
n. | nome | tipo | proprietà | ruolo |
1 | TextBox | EnableViewState=true | campo di immissione | |
2 | RequiredFieldValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Il campo [nome] è obbligatorio | componente di convalida | |
3 | Pulsante | EnableViewState=false CausesValidation=true | pulsante [submit] |
Il campo [RequiredFieldValidator1] serve a visualizzare un messaggio di errore se il campo [txtNom] è vuoto o contiene una sequenza di spazi. Le sue proprietà sono le seguenti:
campo il cui valore deve essere controllato dal componente. Cosa significa il valore di un componente? È il valore dell’attributo [value] del tag HTML corrispondente. Per un [TextBox] sarà il contenuto del campo di immissione, per un [DropDownList] il valore dell’elemento selezionato. | |
booleano - se vero, indica che il contenuto del campo precedente deve essere verificato anche sul lato client. In questo caso, il modulo verrà inviato dal browser solo se non presenta errori. Tuttavia, i controlli di validazione vengono effettuati anche sul server nel caso in cui il client non sia, ad esempio, un browser. | |
il messaggio di errore che il componente deve visualizzare in caso di errore rilevato |
La verifica dei dati della pagina tramite i controlli di validazione viene eseguita solo se il pulsante o il link che ha generato il [POST] della pagina possiede la proprietà [CausesValidation=true]. [true] è il valore predefinito di questa proprietà.
Eseguiamo questa applicazione. Per prima cosa utilizziamo un browser [Mozilla]:

Il codice HTML ricevuto da [Mozilla] è il seguente:
<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>
Si nota che il pulsante [btnEnvoyer] è collegato a una funzione JavaScript tramite il suo attributo [onclick]. Si nota inoltre che la pagina non contiene alcun codice [Javascript]. Il test [typeof(Page_ClientValidate) == 'function'] fallirà e la funzione JavaScript non verrà richiamata. Il modulo verrà quindi inviato al server, che provvederà a effettuare i controlli di validità. Utilizziamo il pulsante [Envoyer] senza specificarne il nome. La risposta del server è la seguente:

Cosa è successo? Il modulo è stato inviato al server. Quest’ultimo ha eseguito il codice di tutti i componenti di validazione presenti nella pagina. In questo caso ce n’è solo uno. Se almeno un componente di convalida rileva un errore, il server restituisce il modulo così come è stato compilato (in realtà, per i componenti con [EnableViewState=true], aggiungendo inoltre un messaggio di errore per ogni componente di convalida che ha rilevato un errore). Questo messaggio è l’attributo [ErrorMessage] del componente di validazione. È proprio questo meccanismo che vediamo all’opera nell’esempio sopra riportato. Se inseriamo qualcosa nel campo [nom], il messaggio di errore non compare più quando si convalida il modulo:

Ora utilizziamo Internet Explorer e richiediamo l’URL [http://localhost/requiredfieldvalidator1.aspx]. Otteniamo la seguente pagina:

Il codice HTML ricevuto da IE è il seguente:
<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>
Si nota che questo codice è molto più lungo di quello ricevuto da [Mozilla]. Non entreremo nei dettagli. La differenza deriva dal fatto che il server ha incluso delle funzioni JavaScript nel documento HTML inviato. Perché due codici HTML diversi, se l’URL richiesto da entrambi i browser è lo stesso? Abbiamo già avuto modo di spiegare che la tecnologia ASP.NET fa sì che il server adatti il documento HTML inviato al cliente in base alle caratteristiche di quest’ultimo. Sul mercato esistono diversi browser che non hanno tutti le stesse funzionalità. I browser Microsoft e Netscape, ad esempio, non utilizzano lo stesso modello a oggetti per il documento che ricevono. Pertanto, il codice JavaScript utilizzato per manipolare tale documento a livello di browser presenta differenze tra i due browser. Allo stesso modo, gli sviluppatori hanno creato versioni successive dei propri browser, migliorandone costantemente le funzionalità. Pertanto, un documento HTML comprensibile da IE5 potrebbe non esserlo da IE3. Abbiamo sopra un esempio di questo adattamento del server a livello del proprio client. Per un motivo che non è stato approfondito in questa sede, il server web ha ritenuto che il client [Mozilla] non fosse in grado di gestire il codice JavaScript di convalida. Pertanto, tale codice non è stato inserito nel documento HTML che gli è stato inviato e la convalida è stata effettuata lato server. Per [IE6], come possiamo vedere, questo codice JavaScript è stato incluso nel documento HTML inviato. Per vederlo in azione, facciamo il seguente esperimento:
- fermiamo il server web
- utilizziamo il pulsante [Envoyer] senza compilare il campo [nom]
Otteniamo la seguente nuova pagina:

È proprio il browser ad aver visualizzato il messaggio di errore. Infatti, il server è inattivo. Possiamo verificarlo inserendo qualcosa nel campo [nom] e confermando. Questa volta la risposta è la seguente:

Cosa è successo? Il browser ha eseguito il codice JavaScript di convalida. Questo codice ha indicato che la pagina era valida. Il browser ha quindi inviato il modulo al server web, che però era spento. Il browser se ne è accorto e ha visualizzato la pagina sopra riportata. Se si riavvia il server, tutto torna alla normalità.
Cosa si può trarre da questo esempio?
- l’importanza del concetto di componente di validazione, che consente di rinviare al client qualsiasi modulo non corretto
- l’utilità del codice [VIEWSTATE], che consente di rinviare il modulo così come è stato compilato
- la capacità del server di adattarsi al proprio client. Quest’ultimo viene identificato dall’intestazione HTTP [User-Agent:] che invia al server. Non è quindi il server a “indovinare” con chi ha a che fare. Questa capacità di adattamento è di grande interesse per lo sviluppatore, che non deve preoccuparsi del tipo di client della propria applicazione.
8.2.3. CompareValidator
Costruiamo la seguente pagina [comparevalidator1.aspx]:

n. | nome | tipo | proprietà | ruolo |
1 | DropDownList | EnableViewState=true | elenco a discesa | |
2 | DropDownList | EnableViewState=true | elenco a discesa | |
3 | CompareValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Scelta 1 non valida ValoreDaConfrontare=? Operatore=Non uguale Tipo=stringa | componente di convalida | |
4 | CompareValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Scelta 2 non valida ControlToCompare=? Operatore=Non uguale Tipo=stringa | componente di convalida | |
5 | Pulsante | EnableViewState=false CausesValidation=true | pulsante [submit] |
Il componente [CompareValidator] serve a confrontare due valori tra loro. Gli operatori utilizzabili sono [Equal, NotEqual, LessThan, LessThanEqual, GreaterThan, GreaterThanEqual]. Il primo valore è definito dalla proprietà [ControlToValidate], il secondo da [ValueToCompare] se il valore precedente deve essere confrontato con una costante, oppure da [ControlToCompare] se deve essere confrontato con il valore di un altro componente. Le proprietà importanti del componente [CompareValidator] sono le seguenti:
campo il cui contenuto deve essere controllato dal componente | |
booleano - il valore "vero" indica che il contenuto del campo precedente deve essere controllato anche sul lato client | |
il messaggio di errore che il componente deve visualizzare in caso di errore rilevato | |
valore con cui deve essere confrontato il valore del campo [ControlToValidate] | |
componente con cui deve essere confrontato il valore del campo [ControlToValidate] | |
operatore di confronto tra i due valori | |
tipo dei valori da confrontare |
Il codice di presentazione di questa pagina è il seguente:
<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>
I vincoli di convalida della pagina sono i seguenti:
- il valore selezionato in [cmbChoix1] deve essere diverso dalla stringa "?". Ciò implica le seguenti proprietà per il componente [CompareValidator1]: Operator=NotEqual, ValueToCompare=?, Type=string
- il valore selezionato in [cmbChoix2] deve essere diverso da quello selezionato in [cmbChoix1]. Ciò implica le seguenti proprietà per il componente [CompareValidator2]: Operator=NotEqual, ControlToCompare=cmbChoix1, Type=string
Eseguiamo questa applicazione. Ecco un esempio di pagina ricevuta durante gli scambi client-server:

Se la stessa pagina viene richiesta da Internet Explorer 6, al suo interno viene incluso del codice JavaScript che ne modifica leggermente il funzionamento. Eventuali errori vengono segnalati non appena l'utente modifica il valore in uno dei menu a tendina. Si tratta di un miglioramento dell'esperienza utente.
8.2.4. CustomValidator, RangeValidator
Creiamo la seguente pagina [customvalidator1.aspx]:

n. | nome | tipo | proprietà | ruolo |
DropDownList | EnableViewState=true | elenco a discesa | ||
CompareValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Diploma non valido Operator=NotEqual ValueToCompare=? Tipo=Stringa | componente di convalida del controllo [1] | ||
TextBox | EnableViewState=false | campo di immissione | ||
CustomValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Precisione del titolo di studio non valida ClientValidationFunction=chkAutreDiplome | componente di convalida del campo [3] | ||
TextBox | EnableViewState=false | campo di immissione | ||
RangeValidator | EnableViewState=false EnableClientScript=true ErrorMessage=L'anno di laurea deve rientrare nell'intervallo [1990,2004] MinValue=1990 MaxValue=2004 Tipo=Intero ControlToValidate=txtAnDiplome | componente di convalida del campo [5] | ||
RequiredFieldValidator | EnableViewState=false EnableClientScript=true ErrorMessage=Anno di conseguimento del titolo di studio richiesto ControlToValidate=txtAnDiplome | componente di convalida del campo [5] | ||
Pulsante | EnableViewState=false CausesValidation=true | pulsante [submit] |
Il campo [RangeValidator] serve a verificare che il valore di un controllo rientri tra i due limiti [MinValue] e [MaxValue]. Le sue proprietà sono le seguenti:
campo il cui valore deve essere verificato dal componente | |
booleano - se vero, indica che il contenuto del campo precedente deve essere verificato anche sul lato client | |
il messaggio di errore che il componente deve visualizzare in caso di errore rilevato | |
valore minimo del campo da controllare | |
valore massimo del campo da controllare | |
tipo del valore del campo da verificare |
Il campo [CustomValidator] consente di effettuare validazioni che i componenti di validazione offerti da ASP.NET non sono in grado di eseguire. Tale validazione viene effettuata tramite una funzione scritta dallo sviluppatore. Questa viene eseguita lato server. Poiché il controllo può essere effettuato anche lato client, lo sviluppatore potrebbe dover sviluppare una funzione JavaScript da includere nel documento HTML. Le sue proprietà sono le seguenti:
campo il cui valore deve essere verificato dal componente | |
booleano - se vero, indica che il contenuto del campo precedente deve essere controllato anche sul lato client | |
il messaggio di errore che il componente deve visualizzare in caso di errore rilevato | |
la funzione da eseguire sul lato client |
Il codice di presentazione della pagina è il seguente:
<%@ 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>
L'attributo [OnServerValidate] del componente [CustomValidator] consente di specificare la funzione incaricata della convalida lato server. Nell'esempio sopra riportato, il componente [CustomValidator1] richiama la seguente procedura [CustomValidator1_ServerValidate_1]:
<%@ Page Language="VB" %>
<script runat="server">
Sub CustomValidator1_ServerValidate_1(sender As Object, e As ServerValidateEventArgs)
' il campo [txtAutreDiplome] deve essere non vuoto 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>
....
Una funzione di convalida associata a un componente [CustomValidator] riceve due parametri:
- sender: oggetto che ha generato l'evento
- e: l'evento. La procedura deve impostare l'attributo [e.IsValid] su vero se i dati verificati sono corretti, su falso in caso contrario.
In questo caso, le verifiche effettuate sono le seguenti:
- l'elenco a discesa [cmbDiplomes] non può avere come valore [?]. Ciò viene verificato dal componente [CompareValidator2]
- l’utente seleziona un titolo di studio dall’elenco a discesa [cmbDiplomes]. Se il titolo di studio non è presente nell’elenco, ha la possibilità di selezionare l’opzione [Autre] dall’elenco. Deve quindi indicare il proprio titolo di studio nel campo di immissione [txtAutreDiplome]. Se in [cmbDiplomes] è selezionato [Autre], il campo [txtAutreDiplome] deve essere compilato. Se né [Autre] né [?] sono selezionati in [cmbDiplomes], allora il campo [txtAutreDiplome] deve essere vuoto. Ciò viene verificato dalla funzione associata al componente [CustomValidator1].
- L'anno di conseguimento del diploma deve rientrare nell'intervallo [1900-2004]. Ciò viene verificato da [RangeValidator1]. Tuttavia, se l'utente non inserisce alcun valore nel campo, la funzione di convalida di [RangeValidator1] non viene utilizzata. Si aggiunge quindi il componente [RequiredFieldValidator2] per verificare la presenza di un contenuto. Questa è una regola generale. Il contenuto di un campo non viene verificato se il campo è vuoto. L'unico caso in cui viene verificato è quello in cui è associato a un componente [RequiredFieldValidator].
Ecco un esempio di esecuzione nel browser [Mozilla]:

Se utilizziamo il browser [IE6], possiamo aggiungere una funzione di convalida lato client per il componente [CustomValidator1]. A tal fine, questo componente presenta le seguenti proprietà:
- EnableClientScript=true
- ClientValidationFunction=chkAutreDiplome
La funzione [chkAutreDiplome ] è la seguente:
<head>
<meta http-equiv="pragma" content="no-cache" />
<script language="javascript">
function chkAutreDiplome(source,args){
// verifica la validità del campo txtAutreDiplome
with(document.frmCandidature){
diplome=cmbDiplomes.options[cmbDiplomes.selectedIndex].text;
args.IsValid= !(diplome=="[Autre]" && txtAutreDiplome.value=="")
&& ! (diplome!="[Autre]" && diplome!="?" && txtAutreDiplome.value!="");
}
}
</script>
</head>
La funzione [chkAutreDiplome] riceve gli stessi due parametri della funzione server [CustomValidator1_ServerValidate_1]:
- source: l'oggetto che ha generato l'evento
- args: l'evento. Quest'ultimo presenta un attributo [IsValid] che deve essere impostato a vero dalla funzione se i dati verificati sono corretti. Un valore falso visualizzerà, nel punto del componente di convalida, il messaggio di errore ad esso associato e il modulo non verrà inviato al server.
8.2.5. RegularExpressionValidator
Creiamo la seguente pagina [regularexpressionvalidator1.aspx]:

n. | nome | tipo | proprietà | ruolo |
TextBox | EnableViewState=true | campo di immissione | ||
RequiredFieldValidator | ControlToValidate=txtMel Display=Dynamic | componente di convalida del controllo [1] | ||
RegularExpressionValidator | ControlToValidate=txtMel Display=Dinamico | componente di convalida del controllo [1] | ||
Pulsante | EnableViewState=false CausesValidation=true | Pulsante [submit] |
In questo caso, vogliamo verificare il formato di un indirizzo e-mail. Lo facciamo utilizzando un componente [RegularExpressionValidator] che consente di verificare la validità di un campo tramite un'espressione regolare. Ricordiamo che un'espressione regolare è un modello di stringa di caratteri. Si verifica quindi il contenuto di un campo rispetto a un modello. Poiché il contenuto di un campo non viene verificato se è vuoto, abbiamo bisogno anche di un componente [RequiredFieldValidator] per verificare che l’indirizzo e-mail non sia vuoto. La classe [RegularExpressionValidator] presenta proprietà analoghe a quelle delle classi dei componenti già esaminati:
campo il cui valore deve essere controllato dal componente | |
booleano - se vero, indica che il contenuto del campo precedente deve essere verificato anche sul lato client | |
il messaggio di errore che il componente deve visualizzare in caso di errore rilevato | |
l'espressione regolare con cui verrà confrontato il contenuto di [ControlToValidate] | |
modalità di visualizzazione: Static: il campo è sempre presente anche se non visualizza alcun messaggio di errore; Dynamic: il campo è presente solo se c'è un messaggio di errore; None: il messaggio di errore non viene visualizzato. Questo campo esiste anche per gli altri componenti, ma finora non era stato utilizzato. |
L'espressione regolare modello di un indirizzo e-mail potrebbe essere la seguente: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*
Un indirizzo e-mail ha la forma [champ1.champ2....@champA.champB...]. Deve esserci obbligatoriamente almeno un campo prima del simbolo @ e almeno due campi dopo. Questi campi sono costituiti da caratteri alfanumerici e dal simbolo -. Il carattere alfanumerico è rappresentato dal simbolo \w. La sequenza [\w-] indica il carattere \w o il carattere -. Il segno + dopo una sequenza S significa che questa può ripetersi una o più volte, il segno * significa che può ripetersi zero o più volte, il segno ? significa che può ripetersi zero o una volta.
Un campo dell’indirizzo e-mail corrisponde al modello [\w-]+. Il fatto che ci debba essere obbligatoriamente almeno un campo prima del segno @ e almeno due dopo, separati dal segno ., corrisponde al modello: [\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+. È possibile consentire all’utente di inserire spazi prima e dopo l’indirizzo. Questi verranno rimossi durante l’elaborazione. Una sequenza di spazi, eventualmente vuota, è rappresentata dal modello \s*. Da qui l'espressione regolare dell'indirizzo e-mail: \s*[\w-]+(\.[\w-]+)*@[\w-]+(\.[\w-]+)+\s*.
Il codice di visualizzazione della pagina è quindi il seguente:
<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
Per motivi estetici, si potrebbe voler raggruppare i messaggi di errore in un unico posto, come nell'esempio seguente [summaryvalidator1.aspx], in cui abbiamo riunito in un'unica pagina tutti gli esempi precedenti:

Tutti i controlli di convalida presentano le seguenti proprietà:
- [Display=Dynamic], il che fa sì che i controlli non occupino spazio nella pagina se il loro messaggio di errore è vuoto
- [EnableClientScript=false] per impedire qualsiasi convalida lato client
- [Text=*]. Questo sarà il messaggio visualizzato in caso di errore, mentre il contenuto dell’attributo [ErrorMessage] viene visualizzato dal controllo [ValidationSummary] che presentiamo di seguito.
Questo insieme di controlli è inserito in un componente [Panel] denominato [vueFormulaire]. In un altro componente [Panel] denominato [vueErreurs], inseriamo un controllo [ValidationSummary]:

n. | nome | tipo | proprietà | ruolo |
1 | ValidationSummary | HeaderText=Si sono verificati i seguenti errori, EnableClientScript=false, ShowSummary=true | visualizza gli errori di tutti i controlli di convalida della pagina | |
2 | LinkButton | CausesValidation=false | link di ritorno al modulo |
Per il link [lnkErreursToFormulaire], non è necessario attivare la convalida poiché questo link non invia alcun valore da verificare.
Quando tutti i dati sono validi, all’utente viene presentata la seguente vista [infos]:

1
n. | nome | tipo | proprietà | ruolo |
1 | Etichetta | messaggio informativo destinato all'utente |
Il codice di presentazione di questa pagina è il seguente:
<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>
Ecco alcuni esempi dei risultati ottenuti. Convalidiamo la vista [formulaire] senza inserire alcun valore:

Il pulsante [Envoyer] ci fornisce la seguente risposta:

È stata visualizzata la vista [erreurs]. Se utilizziamo il link di ritorno al modulo, lo ritroviamo nel seguente stato:

Si tratta della vista [formulaire]. Si noti il carattere [*] accanto ai dati errati. È stato visualizzato il campo [Text] dei controlli di convalida. Se compiliamo correttamente i campi, otterremo la vista [infos]:

Il codice di controllo della pagina è il seguente:
<%@ Page Language="VB" %>
<script runat="server">
' procedura eseguita al caricamento della pagina
Sub page_Load(sender As Object, e As EventArgs)
' alla prima richiesta, viene visualizzata la vista [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)
' insieme di viste
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)
' visualizza la vista modulo
afficheVues(true,false,false)
' esegue nuovamente i controlli di validità
Page.validate
End Sub
Sub btnEnvoyer_Click(sender As Object, e As EventArgs)
' la pagina è valida?
if not Page.IsValid then
' viene visualizzata la vista [erreurs]
afficheVues(false,true,false)
else
' altrimenti la vista [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>
- Nella procedura [Page_Load], eseguita ad ogni richiesta del cliente, visualizziamo la vista [formulaire], mentre le altre vengono nascoste. Ciò avviene solo alla prima richiesta. La procedura richiama una procedura di utilità [afficheVues] alla quale vengono passati tre valori booleani per decidere se visualizzare o meno le tre viste.
- Quando viene chiamata la procedura [btnEnvoyer_Click], le verifiche dei dati sono già state effettuate. Il pulsante [btnEnvoyer], con la proprietà [CausesValidation=true], forza l’esecuzione di tali verifiche. Tutti i controlli di validazione sono stati eseguiti e la loro proprietà [IsValid] è stata impostata. Questa indica se il dato verificato dal controllo era valido o meno. Inoltre, è stata impostata anche la proprietà [IsValid] della pagina stessa. Essa assume il valore [vrai] solo se la proprietà [IsValid] di tutti i controlli di validazione della pagina ha il valore [vrai]. Pertanto, la procedura [btnEnvoyer_Click] inizia verificando se la pagina è valida o meno. Se non è valida, viene visualizzata la vista [erreurs]. Quest’ultima contiene il controllo [ValidationSummary] che riprende gli attributi [ErrorMessage] di tutti i controlli (vedi screenshot sopra). Se la pagina è valida, viene visualizzata la vista [infos] con un messaggio informativo.
- La procedura [lnkErreursToFormulaire_Click] ha il compito di visualizzare la vista [formulaire] nello stato in cui è stata convalidata. Per tutti i campi di immissione della vista [formulaire] che presentano la proprietà [EnableViewState=true], lo stato viene rigenerato automaticamente. Curiosamente, lo stato dei componenti di convalida non viene invece ripristinato. Ci si sarebbe infatti potuti aspettare, al ritorno della vista [erreurs], di vedere i controlli errati visualizzare il proprio campo [Text]. Non è così. Abbiamo quindi forzato la convalida dei dati utilizzando il metodo [Page.Validate] della pagina. Ciò deve essere fatto una volta che il pannello [vueFormulaire] è stato reso visibile. Si hanno quindi in totale due convalide. Nella pratica, ciò andrebbe evitato. In questo caso, l’esempio ci ha permesso di introdurre nuovi concetti sulla convalida della pagina.
8.3. Componenti ListControl e collegamento dei dati
Alcuni dei componenti server esaminati consentono di visualizzare un elenco di valori (DropDownList, ListBox). Altri, che non abbiamo ancora presentato, consentono di visualizzare più elenchi di valori nelle tabelle HTML. Per tutti questi componenti è possibile, tramite programma, associare uno per uno i valori degli elenchi al componente corrispondente. È inoltre possibile associare a questi componenti oggetti più complessi, quali quelli di tipo [Array], [ArrayList], [DataSet], [HashTable], ... il che semplifica il codice che associa i dati al componente. Questa associazione viene chiamata collegamento dati.
Tutti i componenti derivati dalla classe [ListControl] possono essere associati a un elenco di dati. Si tratta dei componenti [DropDownList], [ListBox], [CheckButtonList], [RadioButtonList]. Ciascuno di questi componenti può essere collegato a una fonte di dati. Quest’ultima può essere di vario tipo: [Array], [ArrayList], [DataTable], [DataSet], [HashTable],...., in generale, un oggetto che implementa una delle interfacce IEnumerable, ICollection, IListSource. Ne presenteremo solo alcuni. Un oggetto [DataSet] è un oggetto immagine di un database relazionale. Si tratta quindi di un insieme di tabelle collegate da relazioni. L’oggetto [DataTable] rappresenta una di queste tabelle. La fonte dati assegna le proprietà [Text] e [Value] a ciascuno dei membri [Item] dell’oggetto [ListControl]. Se T è il valore di [Text] e V il valore di [Value], il tag HTML generato per ciascun elemento di [ListControl] è il seguente:
<option value="V">T</option> | |
<input type="checkbox" value="V">T | |
<input type="radio" value="V">T |
L'associazione di un componente [ListControl] a una fonte di dati avviene tramite le seguenti proprietà:
una fonte dati [Array], [ArrayList], [DataTable], [DataSet], [HashTable], ... | |
nel caso in cui la fonte dei dati sia un [DataSet], rappresenta il nome della tabella da utilizzare come fonte dei dati. La vera fonte dei dati è quindi una tabella. | |
nel caso in cui la fonte dei dati sia una tabella ([DataTable], [DataSet]), rappresenta il nome della colonna della tabella che fornirà i propri valori al campo [Text] degli elementi del [ListControl] | |
nel caso in cui la fonte dati sia una tabella ([DataTable],[DataSet]), rappresenta il nome della colonna della tabella che fornirà i propri valori al campo [Value] degli elementi di [ListControl] |
L'associazione di un componente [ListControl] a una fonte di dati non inizializza il componente con i valori della fonte di dati. Ciò avviene tramite l'operazione [ListControl].DataBind.
A seconda della natura della fonte dati, l'associazione di quest'ultima a un componente [ListControl] avverrà in modo diverso:
[ListControl].DataSource=A i campi [Text] e [Value] degli elementi di [ListControl] avranno come valori gli elementi di A | |
[ListControl].DataSource=AL i campi [Text] e [Value] degli elementi di [ListControl] avranno come valori gli elementi di AL | |
[ListControl].DataSource=DT, [ListControl].DataTextField="col1", [ListControl]. DatavalueField ="col2" dove col1 e col2 sono due colonne della tabella DT. I campi [Text] e [Value] degli elementi di [ListControl] assumeranno come valori quelli delle colonne col1 e col2 della tabella DT | |
[ListControl].DataSource=DS, [ListControl].DataSource="table", dove "table" è il nome di una delle tabelle di DS. [ListControl].DataTextField="col1", [ListControl]. DatavalueField ="col2", dove col1 e col2 sono due colonne della tabella "table". I campi [Text] e [Value] degli elementi di [ListControl] avranno come valori quelli delle colonne col1 e col2 della tabella "table" | |
[ListControl].DataSource=HT, [ListControl].DataTextField="key", [ListControl]. DatavalueField ="value", dove [key] e [value] sono rispettivamente le chiavi e i valori di HT. |
Applichiamo queste informazioni all’esempio seguente: [databind1.aspx]:
![]() |
In questo caso abbiamo cinque collegamenti di dati, ciascuno con quattro controlli di tipo [DropDownList], [ListBox], [CheckBoxList] e [RadioButtonList]. I cinque collegamenti esaminati differiscono per le loro fonti di dati:
collegamento | fonte dei dati |
Array | |
ArrayList | |
DataTable | |
DataSet | |
HashTable |
8.3.1. Codice di presentazione dei componenti
Il codice di presentazione dei controlli del collegamento 1 è il seguente:
<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>
Quelli relativi ai collegamenti da 2 a 5 sono identici, tranne che per il numero di collegamento.
8.3.2. Collegamento a una fonte di dati di tipo Array
Il collegamento dei quattro controlli [ListBox] sopra indicati avviene nel modo seguente nella procedura [Page_Load] del codice di controllo:
' i dati globali
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
' procedura eseguita al caricamento della pagina
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' si creano le fonti dei dati che verranno collegati ai componenti
createDataSources
' collegamento a un array [Array]
bindToArray
' collegamento a un elenco [ArrayList]
bindToArrayList
' collegamento a una tabella [DataTable]
bindToDataTable
' collegamento a un gruppo di dati [DataSet]
bindToDataSet
' collegamento a un dizionario [HashTable]
bindToHashTable
end if
End Sub
sub createDataSources
' crea le fonti di dati che saranno collegate ai componenti
' arraylist
dim i as integer
for i=0 to textes.length-1
myDataListe.add(textes(i))
next
' tabella dati
' si definiscono le due colonne
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
' si compila la tabella
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
' dataset - una sola tabella
myDataSet.Tables.Add(myDataTable)
' tabella hash
for i=0 to textes.length-1
myHashTable.add(valeurs(i),textes(i))
next
end sub
' collegamento tabella
sub bindToArray
' l'associazione ai componenti
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
' selezione degli elementi
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
Il collegamento dei controlli ai dati avviene qui solo alla prima richiesta. Successivamente, i controlli manterranno i propri elementi tramite il meccanismo [VIEWSTATE]. Il collegamento viene effettuato nella procedura [bindToArray]. Poiché la fonte dati è di tipo [Array], viene inizializzato solo il campo [DataSource] dei componenti [ListControl]. Il popolamento del controllo con i valori della fonte dati associata viene effettuato tramite il metodo [ListControl].DataBind. Solo in seguito gli oggetti [ListControl] contengono elementi. A quel punto è possibile selezionarne alcuni.
8.3.3. Collegamento a una fonte dati di tipo ArrayList
La fonte dati [myDataListe] viene inizializzata nella procedura [createDataSources]:
' dati globali
dim textes() as string={"un","deux","trois","quatre"}
dim myDataListe as new ArrayList
..
' procedura eseguita al caricamento della pagina
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' si creano le fonti dei dati che verranno collegati ai componenti
createDataSources
...
end if
End Sub
sub createDataSources
' creazione delle fonti dei dati che saranno collegate ai componenti
' arraylist
dim i as integer
for i=0 to textes.length-1
myDataListe.add(textes(i))
next
...
end sub
Il collegamento dei quattro controlli [ListBox] del collegamento 2 avviene come segue nella procedura [bindToArrayList] del codice di controllo:
' collegamento arraylist
sub bindToArrayList
' l'associazione ai componenti
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
' selezione degli elementi
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
Poiché la fonte dati è di tipo [ArrayList], viene inizializzato solo il campo [DataSource] dei componenti [ListControl].
8.3.4. Fonte dati di tipo DataTable
La fonte dati [myDataTable] viene inizializzata nella procedura [createDataSources]:
' i dati globali
dim textes() as string={"un","deux","trois","quatre"}
dim myDataTable as new DataTable("table1")
...
' procedura eseguita al caricamento della pagina
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' si creano le fonti dei dati che verranno collegati ai componenti
createDataSources
...
end if
End Sub
sub createDataSources
' creazione delle fonti dei dati che saranno collegate ai componenti
...
' tabella dati
' si definiscono le due colonne
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
' si compila la tabella
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
Si inizia creando un oggetto [DataTable] con due colonne: [id] e [texte]. La colonna [id] alimenterà il campo [Value] degli elementi di [ListControl], mentre la colonna [texte] alimenterà i rispettivi campi [Text]. La creazione della tabella [DataTable] con due colonne avviene nel modo seguente:
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte",Type.GetType("System.String"))
Si crea quindi una tabella a due colonne:
- la prima, denominata "id", è di tipo intero
- la seconda, denominata "testo", è di tipo stringa
Una volta creata la struttura della tabella, è possibile popolarla con il seguente codice:
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
La colonna [id] conterrà i numeri interi di [0,1,..,n], mentre la colonna [texte] conterrà i valori della tabella [data]. A questo punto, la tabella [dataListe] è compilata. Il collegamento dei quattro controlli [ListBox] del collegamento 3 avviene nel modo seguente nella procedura [bindToDataTable] del codice di controllo:
sub bindToDataTable
' il collegamento ai componenti
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
' selezione degli elementi
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
Ogni componente [ListControl] è collegato alla fonte [myDataTable], assegnando a ciascuno di essi:
La tabella [myDataTable] costituisce la fonte dei dati. La colonna [id] di questa tabella alimenterà i campi [Value] degli elementi dei componenti, mentre la colonna [texte] alimenterà i loro campi [Text].
8.3.5. Fonte dati di tipo DataSet
La fonte dati [myDataSet] viene inizializzata nella procedura [createDataSources]:
' i dati globali
dim myDataTable as new DataTable("table1")
dim myDataSet as new DataSet
...
' procedura eseguita al caricamento della pagina
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' si creano le fonti dei dati che verranno collegati ai componenti
createDataSources
...
end if
End Sub
sub createDataSources
' creazione delle fonti dei dati che saranno collegate ai componenti
' dataset - una sola tabella
myDataSet.Tables.Add(myDataTable)
...
end sub
Un oggetto [DataSet] rappresenta un insieme di tabelle di tipo [DataTable]. Si aggiunge la tabella [myDataTable], creata in precedenza, alla tabella [DataSet]. Il collegamento dei quattro controlli [ListBox] del collegamento 4 avviene come segue nella procedura [bindToDataSet] del codice di controllo:
sub bindToDataSet
' associazione ai componenti
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
' selezione degli elementi
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
Ogni componente [ListControl] è collegato alla fonte dati nel modo seguente:
Il gruppo di dati [myDataSet] costituisce la fonte dati. Poiché questa può comprendere diverse tabelle, in [DataMember] si specifica il nome di quella che verrà utilizzata. La colonna [id] di questa tabella alimenterà i campi [Value] degli elementi dei componenti, mentre la colonna [texte] alimenterà i loro campi [Text].
8.3.6. Fonte dati di tipo HashTable
La fonte dati [myHashTable] viene inizializzata nella procedura [createDataSources]:
' i dati globali
dim textes() as string={"un","deux","trois","quatre"}
dim valeurs() as string={"1","2","3","4"}
dim myHashTable as new HashTable
...
' procedura eseguita al caricamento della pagina
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' vengono create le fonti dei dati che verranno collegati ai componenti
createDataSources
...
end if
End Sub
sub createDataSources
' creazione delle fonti dei dati che saranno collegate ai componenti
...
' tabella hash
for i=0 to textes.length-1
myHashTable.add(valeurs(i),textes(i))
next
end sub
Il dizionario [myHashTable] può essere considerato come una tabella a due colonne denominate "key" e "value". La colonna [key] rappresenta le chiavi del dizionario e la colonna [value] i valori ad esse associati. La colonna [key] è costituita dal contenuto della tabella [valeurs], mentre la colonna [value] dal contenuto della tabella [textes]. Il collegamento di questa fonte ai controlli viene effettuato nella procedura [bindToHashTable]:
sub bindToHashTable
' associazione ai componenti
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
' la selezione degli elementi
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
Per ciascuno dei componenti, il collegamento viene effettuato tramite le istruzioni:
La fonte dei dati è il dizionario [myHashTable]. I valori dei controlli sono forniti dalla colonna [key] del dizionario e i testi dalla colonna [value]. L'inserimento degli elementi del dizionario nei controlli avviene nell'ordine delle chiavi, che è a priori casuale.
8.3.7. Le direttive per l’importazione degli spazi dei nomi
Alcuni spazi dei nomi vengono importati automaticamente in una pagina ASP.NET. Questo non avviene nel caso di "System.Data", dove si trovano le classi [DataTable] e [DataSet]. È quindi necessario importare questa classe. Ciò avviene nel modo seguente:
<%@ Page Language="VB" %>
<%@ import Namespace="System.Data" %>
<script runat="server">
...
</script>
<html>
...
</html>
8.4. Componente DataGrid e collegamento dati
Il componente [DataGrid] consente di visualizzare i dati sotto forma di tabelle, ma va ben oltre questa semplice visualizzazione:
- offre la possibilità di configurare con precisione la «rappresentazione visiva» della tabella
- consente l’aggiornamento della fonte dei dati
Il componente [DataGrid] è un componente potente e complesso al tempo stesso. Lo presenteremo punto per punto.
8.4.1. Visualizzazione di una fonte di dati di tipo Array, ArrayList, DataTable, DataSet
Il componente [DataGrid] consente di visualizzare in una tabella HTML fonti di dati di tipo [Array], [ArrayList], [DataTable], [DataSet]. Per questi quattro tipi di dati, è sufficiente associare la fonte alla proprietà [DataSource] del componente [DataGrid]:
una fonte di dati [Array], [ArrayList], [DataTable], [DataSet], ... | |
nel caso in cui la fonte dati sia un [DataSet], rappresenta il nome della tabella da utilizzare come fonte dati. La vera fonte dati è quindi una tabella. Se questo campo non è compilato, vengono visualizzate tutte le tabelle del [DataSet]. |
Presentiamo ora la pagina [datagrid1.aspx] che mostra l’associazione di un [DataGrid] a quattro diverse fonti di dati:

La pagina contiene quattro componenti [DataGrid] creati con [WebMatrix] nel modo seguente. Si trascina il componente nella posizione desiderata nella scheda [Design]:

Viene quindi disegnata una tabella generica HTML. Le proprietà di un [DataGrid] possono essere definite in fase di progettazione. È ciò che facciamo qui per le sue proprietà di formattazione. A tal fine, selezioniamo il [DataGrid] da configurare. Le sue proprietà vengono visualizzate in una finestra in basso a destra:

Utilizzeremo i due link sopra indicati. Il link [Générateur de propriétés] consente di accedere alle proprietà principali del [DataGrid]:

Deselezioniamo la voce [Afficher l'en-tête] per i quattro componenti [DataGrid] e salviamo la pagina. L’altro link [Mise en forme automatique] consente di scegliere tra diversi stili per la tabella HTML che verrà visualizzata:

Scegliamo [couleur i] per il [DataGrid] n. i. Queste scelte di progettazione vengono tradotte nel codice di presentazione della pagina:
<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>
In modalità progettazione abbiamo impostato solo le proprietà di formattazione. È nel codice di controllo che associamo i dati ai quattro componenti:
<%@ Page Language="VB" %>
<%@ import Namespace="system.data" %>
<script runat="server">
' dati generali
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
' procedura eseguita al caricamento della pagina
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' vengono create le fonti dei dati che verranno collegati ai componenti
createDataSources
' collegamento a un array [Array]
bindToArray
' collegamento a un elenco [ArrayList]
bindToArrayList
' collegamento a una tabella [DataTable]
bindToDataTable
' collegamento a un gruppo di dati [DataSet]
bindToDataSet
end if
End Sub
sub createDataSources
' crea le fonti dati che saranno collegate ai componenti
' arraylist
dim i as integer
for i=0 to textes1.length-1
myDataListe.add(textes1(i))
next
' tabella dati
' si definiscono le due colonne
myDataTable.Columns.Add("id",Type.GetType("System.Int32"))
myDataTable.Columns.Add("texte1",Type.GetType("System.String"))
myDataTable.Columns.Add("texte2",Type.GetType("System.String"))
' si compila la tabella
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
' dataset - una sola tabella
myDataSet.Tables.Add(myDataTable)
end sub
' collegamento tabella
sub bindToArray
with DataGrid1
.DataSource=textes1
.DataBind
end with
end sub
' collegamento arraylist
sub bindToArrayList
with DataGrid2
.DataSource=myDataListe
.DataBind
end with
end sub
' collegamento tabella dati
sub bindToDataTable
with DataGrid3
.DataSource=myDataTable
.DataBind
end with
end sub
' collegamento dataset
sub bindToDataSet
with DataGrid4
.DataSource=myDataSet
.DataBind
end with
end sub
</script>
<html>
...
</html>
Il codice è abbastanza simile a quello dell'esempio precedente, quindi non lo commenteremo in modo particolare. Notiamo tuttavia come viene effettuato il collegamento dei dati. Per ciascuno dei quattro controlli, è sufficiente la seguente sequenza:
dove [source de données] è del tipo [Array] oppure [ArrayList] oppure [DataTable] oppure [DataSet]. Si vede quindi che si tratta di un potente strumento per la visualizzazione dei dati in tabelle:
- la formattazione viene eseguita con [WebMatrix] o qualsiasi altro IDE in fase di progettazione
- il collegamento ai dati viene effettuato nel codice. Con [WebMatrix], può essere effettuato in fase di progettazione se la fonte dei dati è un server SQL o un database ACCESS. In questo caso, si inserirà un componente di tipo [SqlDataSource] o [AccessDataSource] sul foglio. Questo componente può essere collegato in fase di progettazione alla fonte fisica dei dati, ovvero un database SQL Server o un database ACCESS, a seconda dei casi. Se alla proprietà [DataSource] di un componente [DataGrid] viene assegnato un oggetto [SqlDataSource] o [AccessDataSource] collegato a una fonte fisica, in modalità progettazione appariranno i dati effettivi nel componente [DataGrid].
8.5. ViewState dei componenti elenco dati
In questa sede intendiamo illustrare il meccanismo del [VIEWSATE] per i componenti elenco dati. È possibile scegliere tra due metodi per mantenere lo stato di un componente elenco dati tra due richieste del client:
- impostare il suo attributo [VIEWSTATE] su vero
- impostare il suo attributo [VIEWSTATE] su "false" e memorizzare la sua fonte dati nella sessione, in modo da poter ricollegare il componente a tale fonte alla richiesta successiva.
L'esempio seguente illustra alcuni aspetti del meccanismo dei contenitori di dati [VIEWSTATE]. Alla prima richiesta del client, l'applicazione presenta la seguente vista:
![]() |
n. | nome | tipo | proprietà | ruolo |
1 | DataGrid | EnableViewState=true | visualizza una fonte dati S | |
2 | DataGrid | EnableViewState=true | visualizza la stessa fonte S di [DataGrid1] | |
3 | Pulsante | EnableViewState=false | pulsante [submit] |
Il componente [DataGrid1] è gestito dal meccanismo di [VIEWSTATE]. Si sta cercando di capire se questo meccanismo, che rigenera la visualizzazione di [DataGrid1] ad ogni richiesta, rigeneri anche la sua fonte di dati. A tal fine, quest’ultima è collegata al componente [DataGrid2]. La generazione di quest’ultimo ad ogni richiesta avviene tramite un collegamento esplicito alla fonte dati di [DataGrid1]. Esso presenta l’attributo [EnableViewState] anche in [vrai].
Il codice di presentazione [main.aspx] dell’applicazione è il seguente:
<%@ 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>
Il controller [main.aspx.vb] è invece il seguente:
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
' alla prima query la fonte dati viene definita e collegata al primo datagrid
If Not IsPostBack Then
'definire la fonte dati
With DataGrid1
.DataSource = createDataSource()
.DataBind()
End With
End If
' ad ogni query, si collega il datagrid2 alla fonte del primo datagrid
With Datagrid2
.DataSource = DataGrid1.DataSource
.DataBind()
End With
End Sub
Private Function createDataSource() As DataTable
' si inizializza la fonte dati
Dim thèmes As New DataTable
' colonne
With thèmes.Columns
.Add("id", GetType(System.Int32))
.Add("thème", GetType(System.String))
.Add("description", GetType(System.String))
End With
' la colonna id sarà la chiave primaria
thèmes.Constraints.Add("cléprimaire", thèmes.Columns("id"), True)
' righe
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
Il metodo [createDataSource] crea una sorgente S di tipo [DataTable]. Non ci soffermeremo sul suo codice, che non è oggetto dell'esempio. Ciò che ci interessa è il modo in cui vengono costruiti i due componenti [DataGrid]:
- il componente [DataGrid1] viene collegato una volta alla tabella S, in occasione della prima query. Successivamente non lo è più.
- il componente [DataGrid2] viene collegato alla fonte [DataGrid1.DataSource] ad ogni nuova query.
Alla prima richiesta otteniamo la seguente vista:

Come è logico aspettarsi, entrambi i componenti visualizzano la fonte dati a cui sono stati collegati. Utilizziamo il pulsante [Envoyer] per inviare una richiesta [PostBack] al server. La vista ottenuta è quindi la seguente:

Notiamo che il componente [DataGrid1] ha mantenuto il proprio valore, mentre il componente [DataGrid2] no. Spiegazioni:
- ancor prima che la procedura [Page_Load] venga avviata, gli oggetti [DataGrid1] e [DataGrid2] hanno recuperato il valore che avevano durante la richiesta precedente, a causa del meccanismo di [viewstate]. Entrambi, infatti, hanno la proprietà [EnableViewState] impostata su [vrai].
- Viene eseguita la procedura [Page_Load]. Trattandosi di un’operazione [PostBack], il componente [DataGrid1] non viene modificato da [Page_Load] (cfr. codice). Pertanto, mantiene il valore recuperato tramite [viewstate]. È quanto mostra la schermata sopra riportata.
- Il componente [DataGrid2] è invece collegato tramite [DataBind] alla fonte di dati [DataGrid1.DataSource]. Viene quindi ricostruito e il valore che aveva appena recuperato tramite [viewstate] va perso. Sarebbe stato quindi opportuno che la sua proprietà fosse impostata da [EnableViewState] a [faux], al fine di evitare una gestione superflua del suo stato. La schermata sopra mostra che [DataGrid2] è stato collegato a una fonte vuota. Poiché tale fonte è [DataGrid1.DataSource], si deduce che, sebbene il meccanismo di [viewstate] ripristini correttamente la visualizzazione del componente [DataGrid1], non ne ripristini tuttavia le proprietà, come ad esempio [DataSource].
Cosa si può dedurre da questo esempio? È necessario evitare di impostare la proprietà [EnableViewState] di un contenitore di dati su [vrai] se quest’ultimo deve essere collegato (DataBind) a una fonte di dati ad ogni richiesta. Esistono tuttavia alcuni casi in cui, anche in questa situazione, la proprietà [EnableViewState] del contenitore deve essere mantenuta a [vrai], altrimenti gli eventi che si vorrebbero gestire non vengono attivati. Avremo modo di vedere un esempio al riguardo.
Spesso la fonte dati di un contenitore dati cambia nel corso delle richieste. È quindi necessario, ad ogni richiesta, collegare il contenitore alla fonte dati. È frequente che quest’ultima venga inserita in una sessione affinché le richieste possano accedervi. Il nostro secondo esempio illustra questo meccanismo. L’applicazione fornisce una sola vista:
![]() |
n. | nome | tipo | proprietà | ruolo |
1 | DataGrid | EnableViewState=true | visualizza una fonte dati S | |
2 | DataGrid | EnableViewState=false | visualizza la stessa fonte S di [DataGrid1] | |
3 | Pulsante | EnableViewState=false | pulsante [submit] | |
4 | Etichetta | EnableViewState=false | Testi informativi |
Il componente [DataGrid1] viene associato ai dati solo durante la prima richiesta. Manterrà il proprio valore nel corso delle successive richieste grazie al meccanismo del componente [viewstate]. Il componente [DataGrid2] è collegato ad ogni richiesta a una fonte di dati alla quale viene aggiunto un elemento ad ogni nuova richiesta. È quindi necessario collegare (DataBind) il componente [DataGrid2] ad ogni richiesta. Abbiamo quindi impostato il suo attributo da [EnableViewState] a [faux], come consigliato in precedenza. Pertanto, alla seconda richiesta (utilizzando il pulsante [Envoyer]), si ottiene la seguente risposta:

Il componente [DataGrid1] ha mantenuto il suo valore iniziale. Il componente [DataGrid2] presenta un elemento in più. Le tre informazioni [1,2,2] rappresentano il numero della richiesta. Si nota che una delle informazioni è errata. Cercheremo di capire perché.
Il codice di presentazione [main.aspx] dell’applicazione è il seguente:
<%@ 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>
Il codice del controller [main.aspx.vb] è il seguente:
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
' alla prima query, l'origine dati è definita e collegata al primo datagrid
If Not IsPostBack Then
'definire la fonte dati
dtThèmes = createDataSource()
With DataGrid1
.DataSource = dtThèmes
.DataBind()
End With
' memorizzare le informazioni nella sessione
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
' ad ogni richiesta, si aggiunge un nuovo 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)
'collega il datagrid2 alla fonte dati
With Datagrid2
.DataSource = dtThèmes
.DataBind()
End With
' informazioni sul numero di richieste
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
' si memorizzano alcune informazioni nella sessione
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
Non abbiamo riportato il codice del metodo [createDataSource]. È lo stesso dell’applicazione precedente, con la sola differenza che nel codice sorgente sono presenti solo tre righe. Concentriamoci innanzitutto sulla gestione della fonte dati e dei due contenitori:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' alla prima richiesta, la fonte dati viene definita e collegata al primo datagrid
If Not IsPostBack Then
'definire la fonte dati
dtThèmes = createDataSource()
With DataGrid1
.DataSource = dtThèmes
.DataBind()
End With
' memorizzare le informazioni nella sessione
Session("source") = dtThèmes
...
End If
' ad ogni richiesta, si aggiunge un nuovo 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)
'collega il datagrid2 alla fonte dati
With Datagrid2
.DataSource = dtThèmes
.DataBind()
End With
...
End Sub
Il componente [DataGrid1] viene collegato alla fonte di dati S solo durante la prima richiesta (non IsPostBack). In quel momento viene inserito nella sessione. Successivamente non lo sarà più. La fonte di dati S inserita nella sessione viene recuperata ad ogni richiesta e vi viene aggiunta una nuova riga. Il componente [DataGrid2] viene collegato esplicitamente, ad ogni richiesta, alla fonte S. Per questo motivo il suo contenuto aumenta di una riga ad ogni richiesta. Si nota che, dopo aver modificato il contenuto della fonte S, questa non viene reinserita esplicitamente nella sessione tramite un’operazione:
Perché? Quando viene avviata una richiesta, la sessione contiene al suo interno un oggetto Session("source") di tipo [DataTable] che rappresenta la fonte di dati così com’era al momento dell’ultima richiesta. Chiamiamo S l’oggetto Session("source"). Quando scriviamo:
dtThèmes = CType(Session("source"), DataTable)
[dtThèmes] e [S] sono due riferimenti allo stesso oggetto [DataTable]. Pertanto, quando il codice di [Page_Load] aggiunge un elemento alla tabella a cui fa riferimento [dtThèmes], lo aggiunge contemporaneamente anche alla tabella a cui fa riferimento [S]. Al termine dell’esecuzione della pagina, tutti gli oggetti presenti nella sessione verranno salvati e quindi l’oggetto Session("source"), c.a.d. S, c.a.d e [dtThèmes]. È quindi proprio il nuovo contenuto della fonte dati che viene salvato. Non è stato necessario scrivere:
per eseguire questo salvataggio, poiché Session("source") è già uguale a [dtThèmes]. Ciò non vale più quando i dati inseriti nella sessione non sono oggetti, come le strutture [Integer, Float, ...]. È quanto emerge dalla gestione dei contatori delle richieste:
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
' alla prima richiesta, la fonte dati viene definita e collegata al primo datagrid
....
' memorizzare le informazioni nella sessione
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
' ad ogni query, si aggiunge un nuovo tema
....
' Informazioni sul numero di richieste
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
' si memorizzano alcune informazioni nella sessione
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
I contatori delle richieste vengono memorizzati in tre elementi:
- numRequête1 e numRequête2 di tipo [Integer] - [Integer] non è una classe ma una struttura
- numRequête3 di tipo [entier] - [entier] è una classe definita ad hoc
Quando si scrive:
numRequête1 = CType(Session("numRequête1"), Integer)
..
numRequête2 = CType(Session("numRequête2"), Integer)
..
numRequête3 = CType(Session("numRequête3"), entier)
..
- la struttura [Session("numRequête1")] viene copiata in [numRequête1]. Pertanto, quando l'elemento [numRequête1] viene modificato, l'elemento [Session("numRequête1")] non viene modificato
- lo stesso vale per [Session("numRequête2")] e [numRequête2]
- gli elementi [Session("numRequête3")] e [numRequête3] sono entrambi riferimenti allo stesso oggetto di tipo [entier]. L'oggetto a cui si fa riferimento può essere modificato indifferentemente tramite l'uno o l'altro riferimento.
Da ciò si deduce che è superfluo scrivere:
per memorizzare il nuovo valore di [numRequête3] nella sessione. Al contrario, bisognerebbe scrivere:
per memorizzare i nuovi valori delle strutture [numRequête1] e [numRequête2]. Lo facciamo solo per [numRequête2], il che spiega perché nella schermata ottenuta al termine della seconda query il contatore [numRequête1] sia errato.
Si tenga quindi presente che, una volta inserito in una sessione, un dato non deve essere reinserito ripetutamente se è rappresentato da un oggetto. Negli altri casi, è necessario farlo se è stato modificato.
8.6. Visualizzazione di un elenco di dati tramite un DataGrid impaginato e ordinato
Il componente [DataGrid] consente di visualizzare il contenuto di un [DataSet]. Finora abbiamo sempre creato i nostri [DataSet] «a mano». Questa volta utilizziamo un [DataSet] proveniente da un database. Creiamo la seguente applicazione MVC:
![]() |
Le tre viste saranno incorporate nel codice di presentazione del controller [main.aspx] sotto forma di contenitori. Pertanto, questa applicazione ha un'unica pagina [main.aspx].
8.6.1. Le classi di business
La classe [produits] consente di accedere al database ACCESS seguente:

Il codice della classe [produits] è il seguente:
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)
' si memorizza la stringa di connessione
Me.chaineConnexionOLEDB = chaineConnexionOLEDB
End Sub
Public Function getDataSet(ByVal commande As String) As DataSet
' si crea un oggetto DataAdapter per leggere i dati dalla fonte OLEDB
Dim adaptateur As New OleDbDataAdapter(commande, chaineConnexionOLEDB)
' si crea un'immagine in memoria del risultato della selezione
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
' si restituisce il risultato
Return contenu
End Function
End Class
End Namespace
Il database ACCESS sarà gestito tramite un driver OLEDB. Al costruttore della classe [produits] vengono forniti la stringa di connessione, l’identificativo, il driver OLEDB e il database da gestire. La classe [produits] dispone di un metodo [getDataSet] che restituisce un [DataSet] ottenuto dall'esecuzione diuna query SQL [select] il cui testo viene passato come parametro. Nel corso del metodo, avvengono diverse operazioni: creazione della connessione al database, esecuzione della query [select], chiusura della connessione. Tutto ciò può generare un'eccezione, che in questo caso viene gestita. Un programma di test potrebbe essere il seguente:
Option Explicit On
Option Strict On
' spazi dei nomi
Imports System
Imports System.Data
Imports Microsoft.VisualBasic
Namespace st.istia.univangers.fr
' pagina di prova
Module testproduits
Sub Main(ByVal arguments() As String)
' visualizza il contenuto di una tabella dei prodotti
' la tabella si trova in un database ACCESS il cui pg riceve il nome del file
Const syntaxe1 As String = "pg bdACCESS"
' verifica dei parametri del programma
If arguments.Length <> 1 Then
' messaggio di errore
Console.Error.WriteLine(syntaxe1)
' fine
Environment.Exit(1)
End If
' si prepara la stringa di connessione
Dim chaineConnexion As String = "Provider=Microsoft.Jet.OLEDB.4.0; Ole DB Services=-4; Data Source=" + arguments(0)
' creazione di un oggetto prodotti
Dim objProduits As produits = New produits(chaineConnexion)
' si recupera la tabella dei prodotti in un dataset
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
' visualizzazione del contenuto
Dim lignes As DataRowCollection = contenu.Tables(0).Rows
For i As Integer = 0 To lignes.Count - 1
' riga i della tabella
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
La compilazione dei vari elementi di questa applicazione avviene nel modo seguente:
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. Le viste
Ora che abbiamo la classe di accesso ai dati, scriviamo i controller e le viste di questa applicazione web. Vediamo innanzitutto come funziona. La prima vista è la seguente:
![]() |
n. | nome | tipo | proprietà | ruolo |
1 | TextBox | EnableViewState=true | campo di immissione della query SELECT | |
2 | RequiredFieldValidator | EnableViewState=false | verifica la presenza di 1 | |
3 | TextBox | EnableViewState=true | campo di immissione - indica il numero di righe di dati da visualizzare per pagina dei risultati | |
4 | RequiredFieldValidator | EnableViewState=false | verifica la presenza di 3 | |
5 | RangeValidator | EnableViewState=false | verifica che (3) rientri nell'intervallo [1,30] | |
6 | Pulsante | EnableViewState=false | pulsante [submit] |
Chiameremo questa vista "[formulaire]". Essa consente all'utente di eseguire una query SELECT SQL sul database [produits.mdb]. L'esecuzione della query genera una nuova vista:
![]() |
n. | nome | tipo | proprietà | ruolo |
1 | Etichetta | EnableViewState=false | campo informativo | |
2 | RadioButton | EnableViewState=false GroupName=rdTri | consente di scegliere l'ordine di ordinamento | |
3 | DataGrid | EnableViewState=true AllowPaging=true AllowSorting=true | tabella di visualizzazione dei risultati della selezione | |
4 | LinkButton | EnableViewState=false | link-pulsante [submit] |
Chiameremo questa vista "[résultats]". È questa vista che contiene il [DataGrid] che visualizzerà il risultato del comando select SQL. L'utente potrebbe commettere un errore nella sua richiesta. Alcuni errori gli verranno segnalati nella vista [erreurs] grazie ai controlli di validazione.

Altri errori gli verranno segnalati dalla vista [erreurs]:

Viene visualizzata la vista [erreurs]:
![]() |
n. | nome | tipo | proprietà | ruolo |
1 | variabile | codice HTML necessario per la visualizzazione degli errori | ||
3 | LinkButton | EnableViewState=false | pulsante-link [submit] |
Le tre viste dell'applicazione sono tre diversi contenitori (panel) all'interno della stessa pagina [main.aspx]. Il codice di presentazione è il seguente:
<%@ 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. Configurazione di DataGrid
Soffermiamoci sull'impaginazione del componente [DataGrid], un'opzione che incontriamo per la prima volta. Nel codice sopra riportato, tale impaginazione è controllata dai seguenti attributi:
<asp:DataGrid id="DataGrid1" runat="server" PageSize="4" AllowPaging="True" ...>
...
<PagerStyle NextPageText="Suivant" PrevPageText="Précédent" ...></PagerStyle>
</asp:DataGrid></P>
consente l'impaginazione | |
quattro righe di dati per pagina | |
Testo del link per passare alla pagina successiva della fonte dei dati | |
Il testo del link per passare alla pagina precedente della fonte dati |
Queste informazioni possono essere inserite direttamente negli attributi del tag <asp:datagrid>. È inoltre possibile avvalersi di [WebMatrix]. Nella finestra delle proprietà di [DataGrid], seguire il collegamento [Générateur de propriétés]:

Si ottiene la seguente procedura guidata:

Si seleziona l’opzione [Pagination]:

Qui sopra ritroviamo i valori degli attributi di impaginazione del [DataGrid] del codice di presentazione.
Inoltre, abilitiamo l’ordinamento dei dati su una delle colonne di [DataGrid]. Esistono diversi modi per farlo. Uno di questi consiste nel definire la proprietà [AllowSorting=true] nella finestra delle proprietà di [DataGrid]. È possibile utilizzare anche il generatore di proprietà. Qualunque sia il metodo utilizzato, ciò si traduce nella presenza dell’attributo [AllowSorting=true] nel tag <asp:DataGrid> del componente:
<asp:DataGrid id="DataGrid1" runat="server" ... AllowPaging="True" PageSize="4" AllowSorting="True">
8.6.4. I controller
Il controller [global.asax, global.asax.vb] è il seguente:
[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)
' si crea un oggetto prodotti
Dim objProduits As produits
Try
objProduits = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection"))
' si inserisce l'oggetto nell'applicazione
Application("objProduits") = objProduits
' nessun errore
Application("erreur") = False
Catch ex As Exception
'si è verificato un errore, lo si registra nell'applicazione
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
End Class
All'avvio dell'applicazione (Application_Start), creiamo un oggetto [produits] e lo inseriamo nell'applicazione in modo che sia disponibile per tutte le richieste di tutti i client. Se durante la creazione si verifica un'eccezione, questa viene registrata nell'applicazione. La procedura [Application_Start] verrà eseguita una sola volta. Successivamente, il controller [global.asax] non interverrà più. Sarà quindi il controller [main.aspx.vb] a svolgere il lavoro:
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
' componenti della pagina
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
' dati della pagina
Protected erreursHTML As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' si verifica se l'applicazione presenta errori
If CType(Application("erreur"), Boolean) Then
' l'applicazione non si è inizializzata correttamente
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs, False)
Exit Sub
End If
'prima richiesta
If Not IsPostBack Then
' viene visualizzato il modulo vuoto
afficheFormulaire()
End If
End Sub
Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
' visualizza la vista degli errori
erreursHTML = ""
For i As Integer = 0 To erreurs.Count - 1
erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
Next
lnkErreurs.Visible = afficheLien
' viene visualizzata la vista [erreurs]
vueErreurs.Visible = True
vueFormulaire.Visible = False
vueRésultats.Visible = False
End Sub
Private Sub afficheFormulaire()
' viene visualizzata la vista [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)
' si inizializzano i controlli
lblSelect.Text = sqlTexte
With DataGrid1
.DataSource = données
.PageSize = CType(txtPages.Text, Integer)
.CurrentPageIndex = 0
.DataBind()
End With
' viene visualizzata la vista [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
' pagina valida?
If Not Page.IsValid Then
afficheFormulaire()
Exit Sub
End If
' esecuzione della richiesta SELECT del client
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
' tutto a posto - si visualizzano i risultati
afficheRésultats(txtSelect.Text.Trim, données)
' si inseriscono i dati nella sessione
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
' set di viste
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
' cambio di pagina
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
' ordinamento della vista dati
Dim données As DataView = CType(Session("données"), DataView)
données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
' la visualizziamo
With DataGrid1
.CurrentPageIndex = 0
.DataSource = données
.DataBind()
End With
End Sub
End Class
Al caricamento della pagina [Page_Load], si verifica innanzitutto se l'applicazione è riuscita a inizializzarsi correttamente. In caso contrario, viene visualizzata la vista [erreurs] senza link di ritorno al modulo, poiché tale link risulta in quel caso superfluo. Infatti, solo la vista [erreurs] può essere visualizzata se l’applicazione non è riuscita a inizializzarsi correttamente. In caso contrario, viene visualizzata la vista [formulaire] se si tratta della prima richiesta del cliente. Per il resto, lasciamo al lettore il compito di comprendere il codice. Ci soffermiamo solo su tre procedure: la procedura [btnExécuter_Click], che viene eseguita quando l’utente ha richiesto l’esecuzione della richiesta SQL inserita nella vista [formulaire], la procedura [DataGrid1_PageIndexChanged], che viene eseguita quando l’utente utilizza i link [Suivant] e [Précédent] della vista [DataGrid] e la procedura [DataGrid1_SortCommand], che viene eseguita quando l’utente fa clic sul titolo di una colonna per ordinare i dati secondo l’ordine della colonna stessa. Il senso dell’ordine, crescente o decrescente, è determinato dai due pulsanti di opzione di ordinamento.
Nella procedura [btnExécuter_Click], si inizia quindi verificando se la pagina è valida o meno. Quando viene eseguita la procedura [btnExécuter_Click], sono già state effettuate le verifiche relative ai diversi controlli di validazione della pagina. Per ogni controllo di validazione, sono stati impostati due attributi:
impostato su vero se il dato verificato è valido, su falso in caso contrario | |
il messaggio di errore se il dato verificato risulta non valido |
Per la pagina stessa, è stato impostato l’attributo [IsValid]. È impostato su vero solo se tutti i controlli di validazione hanno il loro attributo [IsValid] impostato su vero. In caso contrario, è necessario visualizzare la vista [formulaire]. Questa contiene i controlli di validazione che mostreranno il loro attributo [errorMessage]. Se la pagina è valida, si utilizza l’oggetto di tipo [produits] creato da [Application_Start] per ottenere il [DataSet] corrispondente all’esecuzione della query SELECT SQL. Questo viene trasformato nell'oggetto [DataView]:
Dim données As DataView
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0).DefaultView
...
Si sarebbe potuto lavorare semplicemente con il [DataSet] e scrivere:
Dim données As DataSet
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim)
...
Un oggetto [DataSet] è fondamentalmente un insieme di tabelle collegate tra loro da relazioni. Nella nostra applicazione specifica, il [DataSet] ottenuto dalla classe [produits] contiene una sola tabella, quella derivante dal risultato dell’istruzione [select]. Una tabella può essere ordinata, mentre un [DataSet] non può esserlo; tuttavia, ci interessa ordinare i dati ottenuti. Per lavorare con la tabella risultante dal [select], avremmo potuto scrivere:
Dim données As DataTable
Try
données = CType(Application("objProduits"), produits).getDataSet(txtSelect.Text.Trim).Tables(0)
...
L’oggetto [DataTable], pur rappresentando una tabella di database, non dispone di un metodo di ordinamento. A tal fine è necessario disporre di una vista sulla tabella. Una vista è un oggetto di tipo [DataView]. È possibile avere diverse viste sulla stessa tabella utilizzando dei filtri. Una tabella ha una vista predefinita, ovvero quella in cui non è definito alcun filtro. Essa rappresenta quindi l’intera tabella. Questa vista predefinita si ottiene tramite [DataTable.DefaultView]. È possibile ordinare una vista utilizzando la sua proprietà [sort], sulla quale torneremo in seguito.
Se l’ottenimento del [DataSet] dalla classe [produits] va a buon fine, viene visualizzata la vista [résultats]; in caso contrario, viene visualizzata la vista [erreurs]. La visualizzazione della vista [résultats] avviene tramite la procedura [afficheRésultats], alla quale vengono passati due parametri:
- il testo da inserire nell'etichetta [lblSelect]
- il [DataView] da collegare a [DataGrid1]
Questo esempio ci mostra la grande flessibilità del componente [DataGrid]. È in grado di riconoscere la struttura del [DataView] a cui è collegato e di adattarsi ad essa. Infine, la procedura [btnExécuter_Click] memorizza il [DataView] appena ottenuto nella sessione dell’utente, in modo da poterlo utilizzare quando quest’ultimo richiederà altre pagine dello stesso [DataView].
La procedura [DataGrid1_PageIndexChanged] viene eseguita quando l’utente utilizza i collegamenti [Suivant] e [Précédent] del [DataGrid]. Riceve due parametri:
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.) Handles DataGrid1.PageIndexChanged
l’oggetto all’origine dell’evento – in questo caso, uno dei collegamenti [Suivant] o [Précédent] | |
informazioni sull'evento. L'attributo e.NewPageIndex è il numero della pagina da visualizzare per rispondere alla richiesta del cliente |
Il codice completo del gestore dell’evento è il seguente:
Private Sub DataGrid1_PageIndexChanged(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridPageChangedEventArgs) Handles DataGrid1.PageIndexChanged
' cambio di pagina
With DataGrid1
.CurrentPageIndex = e.NewPageIndex
.DataSource = CType(Session("données"), DataView)
.DataBind()
End With
End Sub
Il componente [DataGrid] ha un attributo [CurrentPageIndex] che indica il numero della pagina che sta visualizzando o che visualizzerà. A questo attributo viene assegnato il valore [NewPageIndex] del parametro [e]. Il [DataGrid] viene quindi associato al [DataView] che era stato memorizzato nella sessione tramite la procedura [btnExécuter_Click].
Ci si potrebbe chiedere se il [DataGrid] necessiti dell’attributo [EnableViewState=true], dato che il suo contenuto viene calcolato dal codice ad ogni nuova esecuzione della pagina. Si potrebbe pensare di no. Tuttavia, se [DataGrid] possiede l’attributo [EnableViewState=false], si osserva che l’evento [DataGrid1.PageIndexChanged] non viene mai attivato. È per questo motivo che è stato mantenuto [EnableViewState=true]. Sappiamo che ciò comporta che il contenuto di [DataGrid] venga inserito nel campo nascosto [__VIEWSTATE] della pagina. Ciò può causare un notevole sovraccarico della pagina se il [DataGrid] è di grandi dimensioni. Se questo aspetto risulta fastidioso, è possibile gestire l’impaginazione autonomamente senza utilizzare l’impaginazione automatica del [DataGrid].
La procedura [DataGrid1_SortCommand] viene eseguita quando l’utente fa clic sul titolo di una delle colonne visualizzate da [DataGrid] per richiedere l’ordinamento dei dati in base a tale colonna. Riceve due parametri:
Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
l'oggetto all'origine dell'evento – in questo caso, uno dei collegamenti [Suivant] o [Précédent] | |
informazioni sull'evento. L'attributo [e.SortExpression] è il nome della colonna su cui è stato cliccato per l'ordinamento |
Il codice completo del gestore dell’evento è il seguente:
Private Sub DataGrid1_SortCommand(ByVal source As Object, ByVal e As System.Web.UI.WebControls.DataGridSortCommandEventArgs) Handles DataGrid1.SortCommand
' ordinamento della vista dati
Dim données As DataView = CType(Session("données"), DataView)
données.Sort = e.SortExpression + " " + CType(IIf(rdCroissant.Checked, "asc", "desc"), String)
' visualizzazione
With DataGrid1
.CurrentPageIndex = 0
.DataSource = données
.DataBind()
End With
End Sub
Si recupera il [DataView] visualizzato dal [DataGrid] nella sessione corrente. È stata la procedura [btnExécuter_Click] a inserirlo lì. Il componente [DataView] possiede una proprietà [Sort] alla quale viene assegnata l’espressione di ordinamento. Quest’ultima segue la sintassi [select ... order by expr1, expr2, ...], in cui ogni [expri] può essere seguito dalla parola chiave [asc] per un ordinamento crescente o da [desc] per un ordinamento decrescente. L'espressione [order by] qui utilizzata è [order by colonne asc/desc]. La proprietà [e.SortExpression] ci fornisce il nome della colonna di [DataGrid] su cui è stato cliccato per l'ordinamento. La stringa [asc/desc] viene impostata in base ai valori dei pulsanti di opzione del gruppo [rdTri]. Una volta impostata l'espressione di ordinamento del [DataView], il [DataGrid] viene associato a quest'ultimo. Si posiziona il [DataGrid] sulla sua prima pagina.
8.7. Componente DataList e collegamento dei dati
Passiamo ora al componente [DataList]. Offre maggiori possibilità di formattazione rispetto al [DataGrid], ma è meno flessibile. Infatti, non è in grado di adattarsi automaticamente alla fonte di dati a cui è collegato. Se si desidera tale adattamento, è necessario implementarlo tramite codice. Se la struttura della fonte dati è nota in anticipo, questo componente offre possibilità di formattazione che possono renderlo preferibile al [DataGrid].
8.7.1. Applicazione
Per illustrare l’utilizzo del [DataList], realizziamo un’applicazione MVC analoga alla precedente:
![]() |
Le tre viste saranno incorporate nel codice di presentazione del controller [main.aspx] sotto forma di contenitori. Pertanto, questa applicazione presenta un'unica pagina [main.aspx].
8.7.2. Le classi di business
La classe [produits] è la stessa di prima.
8.7.3. Le viste
Quando l’utente effettua la sua prima richiesta all’applicazione, ottiene la seguente vista [résultats1]:
![]() |
n. | nome | tipo | proprietà | ruolo |
1 | RadioButton | EnableViewState=false | consente di scegliere uno dei due stili di [DataList] | |
2 | Pulsante | EnableViewState=false | pulsante [submit] | |
3 | DataList | EnableViewState=true | campo di visualizzazione dell'elenco dei dati |
Se l'utente sceglie lo stile n. 2, ottiene la seguente vista [résultats2]:
![]() |
n. | nome | tipo | proprietà | ruolo |
1 | DataList | EnableViewState=true | campo di visualizzazione dell'elenco dei dati |
La vista [erreurs] segnala un problema di accesso alla fonte dati:
![]() |
n. | nome | tipo | proprietà | ruolo |
1 | variabile | codice HTML necessario per la visualizzazione degli errori |
Le tre viste dell'applicazione sono tre contenitori (panel) diversi all'interno della stessa pagina [main.aspx]. Il codice di presentazione è il seguente:
<%@ 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,"prezzo","{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,"prezzo","{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. Configurazione dei componenti [DataList]
Esaminiamo i diversi attributi di un componente [DataList]. Sono molto numerosi e ne presentiamo solo una piccola parte. È possibile definire fino a sette modelli di visualizzazione all'interno di un [DataList]:
modello dell'intestazione del [DataList] | |
modello delle righe che visualizzano gli elementi dell'elenco di dati associato. Solo questo modello è obbligatorio. | |
Per differenziare visivamente gli elementi successivi visualizzati, è possibile utilizzare due modelli: ItemTemplate per l'elemento n, AlternatingItemTemplate per l'elemento n+1 | |
modello dell’elemento selezionato in [DataList] | |
modello del separatore tra due elementi del [DataList] | |
un [DataList] consente di modificare i valori che visualizza. [EditItemTemplate] è il modello di un elemento del [DataList] per il quale ci si trova in modalità "modifica" | |
modello del piè di pagina del [DataList] |
Il componente [DataList1] è stato creato utilizzando [WebMatrix]. Nella sua finestra delle proprietà è stato selezionato il collegamento [Mise en forme automatique]:
![]() | 1234567 ![]() |
Come illustrato sopra, lo schema [Couleur 5] genererà un [DataList] con stili per i seguenti modelli: HeaderTemplate (1), ItemTemplate (2, 6), AlternatingTemplate (3, 5), SelectedItemTemplate (4), FooterTemplate (7). Il codice generato è il seguente:
<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>
Non è stato definito alcun modello. Spetta a noi farlo. Definiamo i seguenti modelli:
| |
|
Si ricorda che il modello [ItemTemplate] è quello relativo alla visualizzazione degli elementi della fonte dati collegata al modello [DataList]. Tale fonte dati è costituita da un insieme di righe di dati, ciascuna delle quali contiene uno o più valori. La riga corrente della fonte dati è rappresentata dall’oggetto [Container.DataItem]. Tale riga presenta delle colonne. [Container.DataItem("col1")] è il valore della colonna "col1" della riga corrente. Per includere questo valore nel codice di presentazione, si scrive <%# Container.DataItem("col") %>. A volte si desidera presentare un elemento della riga corrente in un formato speciale. In questo caso, si desidera visualizzare la colonna "prezzo" della riga corrente in euro. Si utilizza quindi la funzione [DataBinder.Eval], che accetta tre parametri:
- la riga corrente [Container.DataItem]
- il nome della colonna da formattare
- la stringa di formattazione nella forma {0:formato}, dove [format] è uno dei formati accettati dal metodo [string.format].
Pertanto, il codice <%# DataBinder.Eval(Container.DataItem,"prezzo",{0:C}) %> visualizzerà la colonna [prix] della riga corrente in formato monetario (formato C=Currency).
Otterremo quindi un [DataList] che apparirà così:

Nell’esempio sopra riportato, i dati sono stati disposti in modo da avere quattro dati per riga. Ciò si ottiene con i seguenti attributi di [DataList]:
Orizzontale | |
numero di colonne desiderato |
Alla fine, il codice di [DataList1] è quello presentato nel codice di presentazione poco sopra. Lasciamo al lettore il compito di esaminare il codice di presentazione di [DataList2]. Come per il componente [DataGrid], la maggior parte delle proprietà di [DataList] può essere impostata tramite una procedura guidata di [WebMatrix]. A tal fine, si utilizza il collegamento [Générateur de propriétés] nella finestra delle proprietà di [DataList]:
![]() | ![]() |
8.7.5. I controlli
Il controller [global.asax, global.asax.vb] è il seguente:
[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)
' si crea un oggetto "prodotti"
Try
Dim données As DataSet = New produits(ConfigurationSettings.AppSettings("OLEDBStringConnection")).getDataSet("select * from LISTE")
' si inserisce l'oggetto nell'applicazione
Application("données") = données
' nessun errore
Application("erreur") = False
Catch ex As Exception
'si è verificato un errore, lo si registra nell'applicazione
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
End Class
All'avvio dell'applicazione (Application_Start), creiamo un [dataset] a partire dalla classe di business [produits] e lo inseriamo nell'applicazione in modo che sia disponibile per tutte le richieste di tutti i clienti. Se durante questa creazione si verifica un'eccezione, questa viene registrata nell'applicazione. La procedura [Application_Start] verrà eseguita una sola volta. Successivamente, il controller [global.asax] non interverrà più. Sarà quindi il controller [main.aspx.vb] a svolgere il lavoro:
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
' componenti della pagina
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
' dati della pagina
Protected erreursHTML As String
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' si verifica se l'applicazione presenta errori
If CType(Application("erreur"), Boolean) Then
' l'applicazione non si è inizializzata correttamente
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs, False)
Exit Sub
End If
'prima richiesta
If Not IsPostBack Then
' si inizializzano i controlli
With DataList1
.DataSource = CType(Application("données"), DataSet)
.DataBind()
End With
With DataList2
.DataSource = CType(Application("données"), DataSet)
.DataBind()
End With
' si visualizza il modulo vuoto
afficheRésultats(True, False)
End If
End Sub
Private Sub afficheErreurs(ByVal erreurs As ArrayList, ByVal afficheLien As Boolean)
' visualizza la vista degli errori
erreursHTML = ""
For i As Integer = 0 To erreurs.Count - 1
erreursHTML += "<li>" + erreurs(i).ToString + "</li>" + ControlChars.CrLf
Next
' viene visualizzata la vista [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)
' si visualizza la vista [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
' si modifica lo stile
afficheRésultats(RadioButton1.Checked, RadioButton2.Checked)
End Sub
End Class
8.8. Componente Repeater e collegamento dati
Il componente [Repeater] consente di ripetere il codice HTML per ciascuno degli elementi di un elenco di dati. Supponiamo di voler visualizzare un elenco di errori nella forma seguente:

Abbiamo già riscontrato questo problema e lo abbiamo risolto inserendo nel codice di presentazione una variabile nella forma <ul><% =erreursHTML %></ul>, dove il valore di erreursHTML viene calcolato dal controller. Questo valore contiene il codice HTML, ovvero quello di un elenco. Ciò presenta lo svantaggio che, se si desidera modificare la presentazione di questo elenco HTML, si è costretti a intervenire nella parte relativa al controller, il che va contro il principio della separazione tra controller e presentazione. Il componente [Repeater] ci offre una soluzione. Come per il [DataList], è possibile definire i modelli <HeaderTemplate> per l’intestazione, <ItemTemplate> per l’elemento corrente dell’elenco di dati e <FooterTemplate> per la fine dei dati. In questo caso, potremmo avere la seguente definizione per il 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>
Si ricorda che [Container.DataItem] rappresenta una riga di dati se la fonte dei dati ha più colonne. Rappresenta un dato se la fonte ha una sola colonna. Questo sarà il caso in questione. A titolo di esempio, realizziamo la seguente applicazione:

Il codice di presentazione della pagina è il seguente:
<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>
Il codice di controllo è il seguente:
<%@ Page Language="VB" %>
<script runat="server">
' procedura eseguita al caricamento della pagina
Sub page_Load(sender As Object, e As EventArgs)
if not IsPostBack then
' viene creata una fonte di dati
with Repeater1
.DataSource=createDataSource
.DataBind
end with
end if
End Sub
function createDataSource as ArrayList
' crea un 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>
Alla prima richiesta del cliente, associamo un oggetto [ArrayList] al componente [Repeater], che si suppone rappresenti un elenco di errori.
8.9. Application
Riprendiamo qui un'applicazione già trattata con componenti server. L'applicazione consente di effettuare simulazioni di calcolo delle imposte. Si basa su una classe [impot] che non ripeteremo qui. Questa classe necessita di dati che trova in una fonte di dati OLEDB. Per l’esempio, si tratterà di una fonte ACCESS. In questa nuova versione introduciamo le seguenti novità:
- l’utilizzo di componenti di validazione per verificare la validità dei dati
- l'uso di componenti server collegati alle fonti di dati per la visualizzazione dei risultati
8.9.1. La struttura MVC dell’applicazione
La struttura MVC dell'applicazione è la seguente:
![]() |
Le tre viste saranno incorporate nel codice di presentazione del controller [main.aspx] sotto forma di contenitori. Pertanto, questa applicazione presenta un'unica pagina [main.aspx].
8.9.2. Le viste dell'applicazione
La vista [formulaire] è il modulo di inserimento delle informazioni che consentono il calcolo dell’imposta di un utente:

L'utente compila il modulo:

Utilizza il pulsante [Envoyer] per richiedere il calcolo dell'imposta. Viene visualizzata la seguente vista [simulations]:

Torna al modulo tramite il link sopra indicato. Lo ritrova nello stato in cui lo aveva compilato. Può commettere errori di inserimento:

Questi gli vengono segnalati nella schermata [formulaire]:

L'utente corregge quindi i propri errori. Può eseguire nuove simulazioni:

Ottiene quindi la vista [simulations] con una simulazione in più:

Infine, se la fonte dei dati non è disponibile, ciò viene segnalato all’utente nella vista [erreurs]:

8.9.2.1. Il codice di presentazione
Ricordiamo che la pagina [main.aspx] raggruppa tutte le viste. Si tratta di un unico modulo con tre contenitori:
- [panelform] per la vista [formulaire]
- [panelerreurs] per la vista [erreurs]
- [panelsimulations] per la vista [simulations]
Di seguito descriviamo in dettaglio i componenti di questi tre contenitori. Il contenitore [panelform] presenta la seguente rappresentazione visiva:
![]() |
n. | nome | tipo | proprietà | ruolo |
Pannello | vista modulo | |||
RadioButton | GroupName=rdmarie | pulsanti di opzione | ||
CustomValidator | ErrorMessage=Non hai specificato il tuo stato civile EnableClientScript=false | verifica che il programma client abbia effettivamente inviato lo stato civile previsto | ||
TextBox | numero di figli | |||
RequiredFieldValidator | ErrorMessage=Indicare il numero di figli ControlToValidate=txtEnfants | verifica che il campo [txtEnfants] non sia vuoto | ||
RangeValidator | ErrorMessage=Inserisci un numero compreso tra 1 e 30 ControlToValidate=txtEnfants | verifica che il campo [txtEnfants] rientri nell'intervallo [1,30] | ||
TextBox | EnableViewState=true | stipendio annuo | ||
RequiredFieldValidator | ControlToValidate=txtStipendio ErrorMessage=Indica l'importo del tuo stipendio | verifica che il campo [txtSalaire] non sia vuoto | ||
RegularExpressionValidator | ControlToValidate=txtStipendio ErrorMessage=Stipendio non valido Espressione regolare=\s*\d+\s* | verifica che il campo [txtSalaire] sia una sequenza di cifre | ||
Pulsante | CausesValidation=true | pulsante [submit] del modulo - avvia il calcolo dell'imposta | ||
Pulsante | CausesValidation=false | pulsante [submit] del modulo - azzera il modulo |
Potrebbe sorprendere il controllo [cvMarié] incaricato di verificare che l'utente abbia effettivamente selezionato uno dei due pulsanti di opzione. In effetti, non può essere altrimenti se utilizza correttamente il modulo inviato dal server. Poiché nulla può garantirlo, siamo costretti a verificare tutti i parametri inviati. Si noti inoltre l’attributo [CausesValidation=false] del pulsante [btnEffacer]. Infatti, quando l’utente utilizza questo pulsante, non è necessario verificare i dati inviati poiché verranno ignorati.
Tutti i componenti del contenitore hanno la proprietà [EnableViewState=false] tranne [panelForm, txtEnfants, txtSalaire, rdOui, rdNon]. Il contenitore [panelerreurs] ha la seguente rappresentazione visiva:
![]() |
n. | nome | tipo | proprietà | ruolo |
Pannello | EnableViewState=false | Visualizza errori | ||
Ripetitore | EnableViewState=false | visualizza un elenco di errori |
Il componente [rptErreurs] è definito come segue:
<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>
L'elenco dei dati associato al componente [rptErreurs] sarà un oggetto [ArrayList] contenente un elenco di messaggi di errore. Pertanto, come sopra, <%# Container.Dataitem%> indica il messaggio di errore corrente. Il contenitore [panelsimulations] ha la seguente rappresentazione visiva:
![]() |
n. | nome | tipo | proprietà | ruolo |
Pannello | EnableViewState=false | vista simulazioni | ||
LinkButton | EnableViewState=false | link al modulo | ||
DataGrid | EnableViewState=false | incaricato di visualizzare le simulazioni inserite in un oggetto [DataTable] |
Il componente [dgSimulations] è configurato come segue in [Webmatrix]. Nella finestra delle proprietà di [dgSimulations], selezioniamo il collegamento [Mise en forme automatique] e selezioniamo lo schema [Couleur 3]:
![]() | ![]() |
Quindi, sempre nella finestra delle proprietà di [dlgSimulations], selezioniamo il collegamento [Générateur de propriétés]. Richiediamo la visualizzazione delle intestazioni delle colonne:

Selezioniamo l’opzione [Colonnes] per definire le quattro colonne di [DataGrid]:

Deselezioniamo la voce [Créer des colonnes automatiquement ...]. Definiremo noi stessi le quattro colonne del [DataGrid]. Questo sarà associato a un oggetto [DataTable] con quattro colonne denominate rispettivamente "coniuge", "figli", "stipendio", "imposta". Per creare una colonna nel [DataGrid], selezioniamo l’opzione [Colonnes connexe] e utilizziamo il pulsante di creazione come indicato sopra. Viene creata una colonna e possiamo definirne le caratteristiche. La prima colonna della tabella delle simulazioni conterrà la colonna “coniuge” dell’oggetto [DataTable], che sarà associato al [DataGrid]. Questa prima colonna del [DataGrid] è definita come segue nella procedura guidata:

titolo della colonna, in questo caso «Sposato» | |
nome della colonna della fonte dati che verrà visualizzata da questa colonna del [DataGrid]. In questo caso, si tratta della colonna "sposato" del [DataTable]. |
La seconda colonna è definita come segue:
Figli | |
figli |
La terza colonna è definita come segue:
Stipendio annuale | |
stipendio | |
{0:C} - visualizzazione monetaria per ottenere il simbolo dell'euro |
La quarta colonna è definita come segue:
Importo dell'imposta | |
imposta | |
{0:C} - visualizzazione monetaria per ottenere il simbolo dell'euro |
Inseriamo il codice di presentazione e il codice di controllo in due file separati. Il primo sarà in [main.aspx] e il secondo in [main.aspx.vb]. Il codice di [main.aspx] è il seguente:
<%@ 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. Il codice di controllo dell'applicazione
Il codice di controllo dell'applicazione è distribuito nei file [global.asax.vb] e [main.aspx.vb]. Il file [global.asax] è definito come segue:
Il file [global.asax.vb] è il seguente:
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)
' si crea un oggetto Impot
Dim objImpot As impot
Try
objImpot = New impot(New impotsOLEDB(ConfigurationSettings.AppSettings("chaineConnexion")))
' si inserisce l'oggetto nell'applicazione
Application("objImpot") = objImpot
' nessun errore
Application("erreur") = False
Catch ex As Exception
'si è verificato un errore, lo si registra nell'applicazione
Application("erreur") = True
Application("message") = ex.Message
End Try
End Sub
Sub Session_Start(ByVal sender As Object, ByVal e As EventArgs)
' inizio sessione - si crea un elenco di simulazioni vuoto
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
All'avvio dell'applicazione (prima richiesta inviata all'applicazione), viene eseguita la procedura [Application_Start]. Essa cerca di creare un oggetto di tipo [impot] prelevando i dati da una fonte OLEDB. Si invita il lettore a consultare il capitolo 5, dove è stata definita questa classe, qualora l'avesse dimenticata. La creazione dell'oggetto [impot] può fallire se la fonte di dati non è disponibile. In tal caso, l’errore viene memorizzato nell’applicazione affinché tutte le richieste successive sappiano che l’oggetto non è stato inizializzato correttamente. Se la creazione va a buon fine, anche l’oggetto [impot] creato viene memorizzato nell’applicazione. Esso verrà utilizzato da tutte le richieste di calcolo delle imposte. Quando un cliente effettua la sua prima richiesta, la procedura [Application_Start] crea una sessione a suo nome. Questa sessione serve a memorizzare le diverse simulazioni di calcolo delle imposte che il cliente effettuerà. Queste saranno memorizzate in un oggetto [DataTable] associato alla chiave di sessione "simulazioni". All’avvio della sessione, questa chiave viene associata a un oggetto [DataTable] vuoto, ma la cui struttura è stata definita. Le informazioni necessarie all’applicazione sono inserite nel relativo file di configurazione [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>
La chiave [chaineConnexion] indica la stringa di connessione alla fonte OLEDB. L'altra parte del codice di controllo si trova in [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
' variabili locali
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
Il primo evento gestito dal codice è [Page_Load]:
Private Sub Page_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
' innanzitutto, si verifica lo stato dell'applicazione
If CType(Application("erreur"), Boolean) Then
' l'applicazione non è riuscita a inizializzarsi
' viene visualizzata la pagina degli errori
Dim erreurs As New ArrayList
erreurs.Add("Application momentanément indisponible (" + CType(Application("message"), String) + ")")
afficheErreurs(erreurs)
Exit Sub
End If
' nessun errore - alla prima richiesta, si presenta il modulo
If Not IsPostBack Then afficheFormulaire()
End Sub
Prima di iniziare a elaborare la richiesta, ci assicuriamo che l'applicazione sia stata inizializzata correttamente. In caso contrario, viene visualizzata la vista [erreurs] con la procedura [afficheErreurs]. Se si tratta della prima richiesta (IsPostBack=false), visualizziamo la vista [formulaire] con [afficheFormulaire].
La procedura che visualizza la vista [erreurs] è la seguente:
Private Sub afficheErreurs(ByRef erreurs As ArrayList)
' si crea l'elenco degli errori
With rptErreurs
.DataSource = erreurs
.DataBind()
End With
' visualizzazione dei contenitori
panelerreurs.Visible = True
panelform.Visible = False
panelsimulations.Visible = False
Exit Sub
End Sub
La procedura riceve come parametro un elenco di messaggi di errore in [erreurs] di tipo [ArrayList]. Ci limitiamo a collegare questa fonte di dati al componente [rptErreurs] incaricato di visualizzarla.
La procedura che visualizza la vista [formulaire] è la seguente:
Private Sub afficheFormulaire()
' visualizza il modulo
panelform.Visible = True
' gli altri contenitori sono nascosti
panelerreurs.Visible = False
panelsimulations.Visible = False
End Sub
Questa procedura si limita a rendere visibile il contenitore [panelform]. I componenti vengono visualizzati con il valore appena inserito o con quello precedente (VIEWSTATE).
Quando l'utente fa clic sul pulsante [Calculer] nella vista [formulaire], viene eseguito un passaggio da POST a [main.aspx]. Viene eseguita la procedura [Page_Load], seguita dalla procedura [btnCalculer_Click]:
Private Sub btnCalculer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnCalculer.Click
' si verifica la validità dei dati inseriti; se sono presenti errori, questi vengono segnalati
If Not Page.IsValid Then
afficheFormulaire()
Exit Sub
End If
' nessun errore: si calcola l'imposta
Dim impot As Long = CType(Application("objImpot"), impot).calculer( _
rdOui.Checked, CType(txtEnfants.Text, Integer), CType(txtSalaire.Text, Long))
' si aggiunge il risultato alle simulazioni esistenti
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)
' si inseriscono le simulazioni nella sessione
Session.Item("simulations") = simulations
' si visualizza la pagina delle simulazioni
afficheSimulations(simulations, "Retour au formulaire")
End Sub
La procedura inizia con la verifica della validità della pagina. Ricordiamo che, quando viene eseguita la procedura [btnCalculer_Click], i controlli di validità hanno già svolto il loro compito e l'attributo [IsValid] della pagina è stato impostato. Se la pagina non è valida, viene visualizzata nuovamente la vista [formulaire] e la procedura viene terminata. I componenti di convalida della vista [formulaire], i cui attributi vanno da [IsValid] a [false], visualizzeranno il proprio attributo [ErrorMessage]. Se la pagina è valida, l'importo dell'imposta viene calcolato tramite l'oggetto di tipo [impot] che era stato memorizzato nell'applicazione all'avvio della stessa. Questa nuova simulazione viene aggiunta all'elenco delle simulazioni già effettuate e memorizzata nella sessione.
Infine, la vista [simulations] viene visualizzata dalla seguente procedura [afficheSimulations]:
Private Sub afficheSimulations(ByRef simulations As DataTable, ByRef lien As String)
' si collega la griglia dati alla fonte delle simulazioni
With dgSimulations
.DataSource = simulations
.DataBind()
End With
' collegamento
lnkForm2.Text = lien
' le viste
panelsimulations.Visible = True
panelerreurs.Visible = False
panelform.Visible = False
End Sub
La procedura ha due parametri:
- un elenco di simulazioni in [simulations] di tipo [DataTable]
- un testo di collegamento in [lien]
La fonte dati [simulations] è collegata al componente incaricato di visualizzarla. Il testo del link è invece inserito nella proprietà [Text] dell'oggetto [LinkButton] della vista.
Quando l’utente fa clic sul pulsante [Effacer] della vista [formulaire], viene eseguita la procedura [btnEffacer_click] (sempre dopo [Page_Load]):
Private Sub btnEffacer_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles btnEffacer.Click
' visualizza il modulo vuoto
razForm()
afficheFormulaire()
End Sub
Private Sub razForm()
' svuota il modulo
rdOui.Checked = False
rdNon.Checked = True
txtEnfants.Text = ""
txtSalaire.Text = ""
End Sub
Il codice sopra riportato è sufficientemente semplice da non richiedere commenti. Resta da gestire il clic sui link delle viste [erreurs] e [simulations]:
Private Sub lnkForm1_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm1.Click
' visualizza il modulo
afficheFormulaire()
End Sub
Private Sub lnkForm2_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles lnkForm2.Click
' visualizza il modulo
afficheFormulaire()
End Sub
Entrambe le procedure si limitano a visualizzare la vista [formulaire]. Sappiamo che i campi di tale vista assumeranno un valore che corrisponde al valore inviato per essi oppure al loro valore precedente. Poiché in questo caso il POST del cliente non invia alcun valore per i campi del modulo, questi riprenderanno il loro valore precedente. Il modulo viene quindi visualizzato con i valori inseriti dall’utente.
8.9.4. Test
Tutti i file necessari all’applicazione sono collocati in una cartella <application-path>: ![]() | La cartella [bin] contiene la DLL con le classi [impot], [impotsData], [impotsOLEDB] necessarie all’applicazione: |
Il lettore potrà, se lo desidera, rileggere il capitolo 5 in cui viene spiegato come creare il file [impot.dll] sopra indicato. Fatto ciò, il server Cassini viene avviato con i parametri (<application-path>,/impots6). Si richiede l'URL [http://impots6/main.aspx] con un browser:

Se si rinomina il file ACCESS [impots.mdb] in [impots1.mdb], si otterrà la seguente pagina:

8.9.5. Conclusione
Abbiamo un'applicazione MVC che utilizza esclusivamente componenti server. Il loro utilizzo ha permesso di separare completamente la parte di presentazione dell’applicazione dalla sua parte di controllo. Ciò non era ancora stato possibile fino ad ora, quando il codice di presentazione conteneva variabili calcolate dal codice di controllo e aventi un valore contenente codice HTML. Ora non è più così.






















