11. L'applicazione [SimuPaie] – versione 7 – ASP.NET / multi-vista / multi-pagina
Letture consigliate: riferimento [1], Sviluppo WEB con ASP.NET 1.1 paragrafo: Esempi
Esaminiamo ora una versione funzionalmente identica all’applicazione a tre livelli ASP.NET ([pam-v4-3tier-nhibernate-multivues-monopage]) analizzata in precedenza, ma ne modifichiamo l’architettura nel modo seguente: mentre nella versione precedente le viste erano implementate da un'unica pagina ASPX, qui saranno implementate da tre pagine ASPX.
L’architettura dell’applicazione precedente era la seguente:
![]() |
Qui abbiamo un'architettura MVC (Modello – Vista – Controller):
- [Default.aspx.cs] contiene il codice del controller. La pagina [Default.aspx] è l’unico punto di contatto con il client. È attraverso di essa che passano tutte le richieste del client.
- [Saisies, Simulation, Simulations, ...] sono le viste. Queste viste sono implementate qui tramite i componenti [View] della pagina [Default.aspx].
L'architettura della nuova versione sarà la seguente:
![]() |
- solo il livello [web] subisce modifiche
- le visualizzazioni (cioè ciò che viene mostrato all'utente) non cambiano.
- Il codice del controller, che nella versione precedente era interamente contenuto in [Default.aspx.cs], è ora distribuito su più pagine:
- [MasterPage.master]: una pagina che raggruppa gli elementi comuni alle diverse viste: la barra superiore con le relative opzioni di menu
- [Formulaire.aspx]: la pagina che presenta il modulo di simulazione e gestisce le azioni che avvengono su tale modulo
- [Simulations.aspx]: la pagina che presenta l’elenco delle simulazioni e gestisce le azioni che avvengono su questa stessa pagina
- [Erreurs.aspx]: la pagina visualizzata in caso di errore di inizializzazione dell’applicazione. Su questa pagina non sono possibili azioni.
Si può considerare che si tratti di un’architettura MVC a controller multipli, mentre l’architettura della versione precedente era un’architettura MVC a controller singolo.
L'elaborazione di una richiesta da parte di un cliente si svolge secondo le seguenti fasi:
- il cliente invia una richiesta all’applicazione. La invia a una delle due pagine [Formulaire.aspx, Simulations.aspx].
- la pagina richiesta elabora tale richiesta. A tal fine, può aver bisogno dell’aiuto del livello [métier], che a sua volta può aver bisogno del livello [dao] se è necessario scambiare dati con il database. L’applicazione riceve una risposta dal livello [métier].
- In base a tale risposta, sceglie (3) la vista (= la risposta) da inviare al cliente, fornendogli (4) le informazioni (il modello) di cui ha bisogno.
- La risposta viene inviata al cliente (5)
11.1. Le viste dell’applicazione
Le diverse viste presentate all’utente sono le seguenti:
- - la vista [VueSaisies] che presenta il modulo di simulazione

- - la vista [VueSimulation] utilizzata per visualizzare il risultato dettagliato della simulazione:

- - la vista [VueSimulations] che fornisce l’elenco delle simulazioni effettuate dal cliente

- - la vista [VueSimulationsVides] che indica che il cliente non ha o non ha più simulazioni:

- la vista [VueErreurs] che segnala un errore di inizializzazione dell'applicazione:

11.2. Generazione delle viste in un contesto multi-controller
Nella versione precedente, tutte le viste venivano generate a partire dall’unica pagina [Default.aspx]. Quest’ultima conteneva due componenti [MultiView] e le viste erano costituite dall’unione di uno o due componenti [View] appartenenti a questi due componenti [MultiView].
Efficace quando le viste sono poche, questa architettura raggiunge i propri limiti non appena il numero dei componenti che formano le diverse viste diventa elevato: infatti, ad ogni richiesta effettuata all’unica pagina [Default.aspx], tutti i suoi componenti vengono istanziati, anche se solo alcuni di essi verranno utilizzati per generare la risposta all’utente. Ad ogni nuova richiesta viene quindi svolto un lavoro superfluo, che diventa penalizzante quando il numero totale dei componenti della pagina è elevato.
Una soluzione consiste quindi nel distribuire le viste su pagine diverse. È ciò che facciamo in questo caso. Esaminiamo due diversi casi di generazione delle viste:
- la richiesta viene effettuata a una pagina P1 e questa genera la risposta
- la richiesta viene inviata a una pagina P1 e questa richiede a una pagina P2 di generare la risposta
11.2.1. Caso 1: una pagina controller/vista
Nel caso 1, si torna all’architettura a controller singolo della versione precedente, in cui la pagina [Default.aspx] è la pagina P1:
![]() |
- il client invia una richiesta alla pagina P1 (1)
- la pagina P1 elabora questa richiesta. A tal fine, potrebbe aver bisogno dell’aiuto del livello [métier] (2), che a sua volta potrebbe aver bisogno del livello [dao] se è necessario scambiare dati con il database. L'applicazione riceve una risposta dal livello [métier].
- In base a questa, sceglie (3) la vista (= la risposta) da inviare al cliente, fornendogli (4) le informazioni (il modello) di cui ha bisogno. Si tratta, in questo caso, di scegliere nella pagina P1 i componenti [Panel] o [View] da visualizzare e di inizializzare i componenti in essi contenuti.
- La risposta viene inviata al client (5)
Ecco due esempi tratti dall’applicazione in esame:
[page Formulaire.aspx]
![]() |
- in [1]: l’utente, dopo aver richiesto la pagina [Formulaire.aspx], richiede una simulazione
- in [2]: la pagina [Formulaire.aspx] ha elaborato questa richiesta e ha generato autonomamente la risposta visualizzando un componente [View] che non era stato visualizzato in [1]
[page Simulations.aspx]
![]() |
- in [1]: l’utente, dopo aver richiesto la pagina [Simulations.aspx], desidera rimuovere una simulazione
- in [2]: la pagina [Simulations.aspx] ha elaborato questa richiesta e ha generato autonomamente la risposta, visualizzando nuovamente l’elenco delle simulazioni.
2 ![]() |
11.2.2. Caso 2: una pagina con 1 controller, una pagina con 2 controller / vista
Il caso 2 può riguardare diverse architetture. Sceglieremo la seguente:
![]() |
- il client invia una richiesta alla pagina P1 (1)
- la pagina P1 elabora questa richiesta. A tal fine, potrebbe aver bisogno dell’aiuto del livello [métier] (2), che a sua volta potrebbe aver bisogno del livello [dao] se è necessario scambiare dati con il database. L'applicazione riceve una risposta dal livello [métier].
- In base a questa, sceglie (3) la vista (= la risposta) da inviare al cliente, fornendogli (4) le informazioni (il modello) di cui ha bisogno. In questo caso, la vista da generare deve essere creata da una pagina diversa da P1, ovvero dalla pagina P2. Per eseguire le operazioni (3) e (4), la pagina P1 ha due possibilità:
- effettuare un trasferimento di esecuzione alla pagina P2 tramite l'operazione [Server.Transfer(" P2.aspx ")]. In questo caso, può inserire il modello destinato alla pagina P2 nel contesto della richiesta [Context.Items[" clé "]=valeur] o nella sessione dell'utente [Session.[" clé "]=valeur]. La pagina P2 verrà quindi istanziata e, durante l’elaborazione del suo evento Load, ad esempio, potrà recuperare le informazioni trasmesse dalla pagina P1 tramite le operazioni [valeur=(Type)Context.Items[" clé "]] oppure [valeur=(Type)Session[" clé "]], a seconda dei casi, dove Type è il tipo del valore associato alla chiave. La trasmissione dei valori tramite il contesto Context è la più appropriata se non è necessario che i valori del modello vengano conservati per una futura richiesta del cliente.
- chiedere al cliente di reindirizzarsi alla pagina P2 tramite l’operazione [Response.Redirect(" P2.aspx ")]. In questo caso, la pagina P1 inserirà il modello destinato alla pagina P2 nella sessione, poiché il contesto di richiesta Context viene eliminato al termine di ogni richiesta. In questo caso, però, il reindirizzamento provocherà la conclusione della prima richiesta del client verso P1 e l’invio di una seconda richiesta da parte dello stesso client, questa volta verso P2. Si hanno quindi due richieste successive. È noto che la sessione è uno dei modi per conservare la “memoria” tra una richiesta e l’altra. Esistono altre soluzioni oltre alla sessione.
- A prescindere dal modo in cui P2 subentra, si ricade poi nel caso 1: P2 ha ricevuto una richiesta che elaborerà (5) e genererà essa stessa la risposta (6, 7). Si può anche immaginare che la pagina P2, dopo aver elaborato la richiesta, passi il testimone a una pagina P3, e così via.
Ecco un esempio tratto dall’applicazione in esame:
![]() |
- in [1]: l’utente che ha richiesto la pagina [Formulaire.aspx] chiede di visualizzare l’elenco delle simulazioni
- in [2]: la pagina [Formulaire.aspx] elabora questa richiesta e reindirizza il client alla pagina [Simulations.aspx]. È quest’ultima a fornire la risposta all’utente. Invece di chiedere al client di reindirizzarsi, la pagina [Formulaire.aspx] avrebbe potuto inoltrare la richiesta del client alla pagina [Simulations.aspx]. In questo caso, in [2] si sarebbe visto lo stesso URL presente in [1]. Infatti, un browser visualizza sempre l’ultimo URL richiesto:
- l’azione richiesta in [1] è destinata alla pagina [Formulaire.aspx]. Il browser effettua un POST verso questa pagina.
- Se la pagina [Formulaire.aspx] elabora la richiesta e poi la inoltra tramite [Server.Transfer(" Simulations.aspx ")] alla pagina [Simulations.aspx], si rimane nella stessa richiesta. Il browser visualizzerà quindi, in [2], l’URL proveniente da [Formulaire.aspx], verso cui è avvenuto l’POST.
- Se la pagina [Formulaire.aspx] elabora la richiesta e poi la reindirizza tramite [Response.Redirect(" Simulations.aspx ")] alla pagina [Simulations.aspx], il browser effettua quindi una seconda richiesta, un GET verso [Simulations.aspx]. Il browser visualizzerà quindi in [2] il URL proveniente da [Simulations.aspx], verso il quale è stato effettuato il GET. È ciò che ci mostra la schermata [2] qui sopra.
11.3. Il progetto Visual Web Developer del livello [web]
Il progetto Visual Web Developer del livello [web] è il seguente:
![]() |
- in [1] si trova:
- il file di configurazione [Web.config] dell’applicazione – è identico a quello dell’applicazione [pam-v4-3tier-nhibernate-multivues-monopage].
- la pagina [Default.aspx] – si limita a reindirizzare il cliente alla pagina [Formulaire.aspx]
- la pagina [Formulaire.aspx], che presenta all’utente il modulo di simulazione e gestisce le azioni relative a tale modulo
- la pagina [Simulations.aspx], che presenta all’utente l’elenco delle sue simulazioni e gestisce le azioni relative a questa pagina
- la pagina [Erreurs.aspx], che presenta all’utente una pagina che segnala un errore verificatosi all’avvio dell’applicazione web.
- In [2] sono riportati i riferimenti del progetto.
Torniamo all’architettura del nuovo progetto:
![]() |
Rispetto al progetto [pam-v4-3tier-nhibernate-multivues-monopage], cambiano solo le viste. Il nuovo progetto riprende quindi alcuni dei file di quel progetto:
- il file di configurazione [Web.config]
- i file DLL referenziati da [pam-dao-nhibernate, pam-metier-dao-nhibernate, Spring.Core, NHibernate]
- la classe globale dell’applicazione [Global.asax]
- le cartelle [images, ressources, pam]
Per garantire la coerenza con il progetto in fase di sviluppo, faremo in modo che lo spazio dei nomi delle viste e della classe globale dell’applicazione sia [pam-v7]:
![]() |
11.4. Il codice di presentazione delle pagine
11.4.1. La pagina master [MasterPage.master]
Le viste dell’applicazione presentate nel paragrafo 11.1 presentano parti comuni che possono essere raggruppate in una pagina master, denominata Master Page in Visual Studio. Prendiamo ad esempio le viste [VueSaisies] e [VueSimulationsVides] riportate di seguito, generate rispettivamente dalle pagine [Formulaire.aspx] e [Simulations.aspx]:
![]() |
Queste due viste hanno in comune la barra superiore (Titolo e Opzioni di menu). Lo stesso vale per tutte le viste che verranno presentate all’utente: avranno tutte la stessa barra superiore. Affinché pagine diverse condividano lo stesso frammento di presentazione, esistono diverse soluzioni, tra cui le seguenti:
- inserire questo frammento comune in un componente utente. Questa era la tecnica principale utilizzata con ASP.NET 1.1
- inserire questo frammento comune in una pagina master. Questa tecnica è stata introdotta con ASP.NET 2.0. È quella che utilizziamo in questo caso.
Per creare una pagina master in un’applicazione web, è possibile procedere come segue:
- clic destro sul progetto / Aggiungi un nuovo elemento / Pagina master:
![]() |
L’aggiunta di una pagina master aggiunge per impostazione predefinita tre file all’applicazione web:
- [MasterPage.master]: il codice di presentazione della pagina master
- [MasterPage.master.cs]: il codice di controllo della pagina master
- [Masterpage.Master.designer.cs]: la dichiarazione dei componenti della pagina master
Il codice generato da Visual Studio in [MasterPage.master] è il seguente:
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="MasterPage.master.cs" Inherits="pam_v7.MasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head runat="server">
<title>Untitled Page</title>
<asp:ContentPlaceHolder id="head" runat="server">
</asp:ContentPlaceHolder>
</head>
<body>
<form id="form1" runat="server">
<div>
<asp:ContentPlaceHolder id="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</div>
</form>
</body>
</html>
- riga 1: il tag <%@ Master ... %> serve a definire la pagina come pagina master. Il codice di controllo della pagina si troverà nel file definito dall'attributo CodeBehind, e la pagina erediterà la classe definita dall'attributo Inherits.
- righe 12-18: il modulo della pagina master
- righe 14-16: un contenitore vuoto che, nella nostra applicazione, conterrà una delle pagine [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Il cliente riceve in risposta, sempre la stessa pagina, la pagina Master, nella quale il contenitore [ContentPlaceHolder1] riceverà un flusso HTML fornito da una delle pagine [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Pertanto, per modificare l’aspetto delle pagine inviate ai clienti, è sufficiente modificare l’aspetto della pagina Master.
- righe 8-9: un contenitore vuoto con cui le pagine "figlie" potranno personalizzare l’intestazione <head>...</head>.
La rappresentazione visiva (scheda Design) di questo codice sorgente è mostrata in (1) qui sotto. Inoltre, è possibile aggiungere tutti i contenitori che si desidera, grazie al componente [ContentPlaceHolder] (2) della barra degli strumenti [Standard].
![]() |
Il codice di controllo generato da Visual Studio in [MasterPage.master.cs] è il seguente:
using System;
public partial class MasterPage : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
- riga 3: la classe a cui fa riferimento l'attributo [Inherits] della direttiva <%@ Master ... %> della pagina [MasterPage.master] deriva dalla classe [System.Web.UI.MasterPage]
Sopra, vediamo la presenza del metodo Page_Load che gestisce l’evento Load della pagina master. La pagina master conterrà al suo interno un’altra pagina. In quale ordine si verificano gli eventi Load delle due pagine? Si tratta di una regola generale: l’evento Load di un componente si verifica prima di quello del suo contenitore. In questo caso, l’evento Load della pagina inserita nella pagina master avrà quindi luogo prima di quello della pagina master stessa.
Per generare una pagina che abbia come pagina master la precedente pagina [MasterPage.master], si potrà procedere come segue:
![]() |
- in [1]: clic destro sulla pagina master, quindi opzione [Ajouter une page de contenu]
- in [2]: viene generata una pagina predefinita, in questo caso [WebForm1.aspx].
Il codice di presentazione [WebForm1.aspx] è il seguente:
<%@ Page Title="" Language="C#" MasterPageFile="~/MasterPage.Master" AutoEventWireup="true" CodeBehind="WebForm1.aspx.cs" Inherits="pam_v7.WebForm1" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="server">
</asp:Content>
- riga 1: la direttiva Page e i suoi attributi
- MasterPageFile: indica il file della pagina master della pagina descritta dalla direttiva. Il segno ~ indica la cartella del progetto.
- gli altri parametri sono quelli usuali di una pagina web ASP
- righe 2-3: i tag <asp:Content> sono collegati uno a uno alle direttive <asp:ContentPlaceHolder> della pagina master tramite l’attributo ContentPlaceHolderID. I componenti inseriti tra le righe 2-3 sopra indicate, al momento dell’esecuzione, verranno inseriti nel contenitore ID ContentPlaceHolder1 della pagina master.
Rinominando la pagina [WebForm1.aspx] così generata, è possibile creare le diverse pagine utilizzando [MasterPage.master] come pagina master.
Per la nostra applicazione [SimuPaie], l’aspetto visivo della pagina master sarà il seguente:
![]() |
N. | Tipo | Nome | Ruolo |
Pannello (rosa sopra) | intestazione | intestazione della pagina | |
Pannello (giallo sopra) | contenuto | contenuto della pagina | |
LinkButton | LinkButtonFaireSimulation | richiede il calcolo della simulazione | |
LinkButton | LinkButtonEffacerSimulation | cancella il modulo di inserimento dati | |
LinkButton | LinkButtonVoirSimulations | visualizza l'elenco delle simulazioni già effettuate | |
LinkButton | LinkButtonFormulaireSimulation | torna al modulo di inserimento dati | |
LinkButton | LinkButtonEnregistrerSimulation | salva la simulazione corrente nell'elenco delle simulazioni | |
LinkButton | LinkButtonTerminerSession | termina la sessione corrente |
Il codice sorgente corrispondente è il seguente:
<%@ Master Language="C#" AutoEventWireup="true" CodeBehind="MasterPage.master.cs" Inherits="pam_v7.MasterPage" %>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head id="Head1" runat="server">
<title>Application PAM</title>
</head>
<body background="ressources/standard.jpg">
<form id="form1" runat="server">
<asp:ScriptManager ID="ScriptManager1" runat="server" EnablePartialRendering="true" />
<asp:UpdatePanel runat="server" ID="UpdatePanelPam" UpdateMode="Conditional">
<ContentTemplate>
<asp:Panel ID="entete" runat="server" BackColor="#FFE0C0">
<table>
<tr>
<td>
<h2>
Simulateur de calcul de paie</h2>
</td>
<td>
<label>
 </label>
<asp:UpdateProgress ID="UpdateProgress1" runat="server">
<ProgressTemplate>
<img alt="" src="images/indicator.gif" />
<asp:Label ID="Label5" runat="server" BackColor="#FF8000"
EnableViewState="False" Text="Calcul en cours. Patientez ....">
</asp:Label>
</ProgressTemplate>
</asp:UpdateProgress>
</td>
<td>
<asp:LinkButton ID="LinkButtonFaireSimulation" runat="server"
CausesValidation="False">| Faire la simulation<br />
</asp:LinkButton>
<asp:LinkButton ID="LinkButtonEffacerSimulation" runat="server"
CausesValidation="False">| Effacer la simulation<br />
</asp:LinkButton>
<asp:LinkButton ID="LinkButtonVoirSimulations" runat="server"
CausesValidation="False">| Voir les simulations<br />
</asp:LinkButton>
<asp:LinkButton ID="LinkButtonFormulaireSimulation" runat="server"
CausesValidation="False">| Retour au formulaire de simulation<br />
</asp:LinkButton>
<asp:LinkButton ID="LinkButtonEnregistrerSimulation" runat="server"
CausesValidation="False">| Enregistrer la simulation<br />
</asp:LinkButton>
<asp:LinkButton ID="LinkButtonTerminerSession" runat="server"
CausesValidation="False">| Terminer la session<br />
</asp:LinkButton>
</td>
</tr>
</table>
<hr />
</asp:Panel>
<div>
<asp:Panel ID="contenu" runat="server" BackColor="#FFFFC0">
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</asp:Panel>
</div>
</ContentTemplate>
</asp:UpdatePanel>
</form>
</body>
</html>
- riga 1: si noti il nome della classe della pagina master: MasterPage
- riga 8: si definisce un'immagine di sfondo per la pagina.
- righe 9-64: il modulo
- riga 10: il componente ScriptManager necessario per gli effetti Ajax
- righe 11-63: il contenitore AJax
- righe 12-62: il contenuto con funzionalità Ajax
- righe 13-55: il componente Panel [entete]
- righe 57-60: il componente Panel [contenu]
- righe 58-59: il componente ID [ContentPlaceHolder1] che conterrà la pagina incapsulata [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]
Per creare questa pagina, sarà possibile inserire nel pannello [entete] il codice ASPX della vista [VueEntete] della pagina [Default.aspx] della versione [pam-v4-3tier-nhibernate-multivues-monopage], descritta al paragrafo 8.5.2.
11.4.2. La pagina [Formulaire.aspx]
Per generare questa pagina, si seguirà il metodo illustrato al paragrafo 11.4.1 e si rinominerà [Formulaire.aspx] la pagina [WebForm1.aspx] così generata. L'aspetto visivo della pagina [Formulaire.aspx] in fase di costruzione sarà il seguente:
![]() |
L'aspetto visivo della pagina [Formulaire.aspx] presenta due elementi:
- in [1] la pagina master con il suo contenitore [ContentPlaceHolder1] (2)
- in [2] i componenti inseriti nel contenitore [ContentPlaceHolder1]. Questi sono identici a quelli dell'applicazione precedente.
Il codice sorgente di questa pagina è il seguente:
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
CodeBehind="Formulaire.aspx.cs" Inherits="pam_v7.PageFormulaire" Title="Simulation de calcul de paie : formulaire" %>
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<div>
<table>
<tr>
<td>
Employé
</td>
<td>
Heures travaillées
</td>
<td>
Jours travaillés
</td>
<td>
</td>
</tr>
...
</asp:Content>
- riga 1: la direttiva Page con il suo attributo MasterPageFile
- riga 4: la classe di controllo della pagina master può esporre campi e proprietà pubblici. Questi sono accessibili alle pagine incapsulate con la sintassi Master.[champ] o Master.[propriété]. La proprietà Master della pagina indica la pagina master sotto forma di un'istanza di tipo [System.Web.UI.MasterPage]. Pertanto, nel nostro esempio, si dovrebbe in realtà scrivere (MasterPage)(Master).[champ] oppure (MasterPage)(Master).[propriété]. È possibile evitare questa conversione di tipo inserendo nella pagina la direttiva MasterType alla riga 4. L'attributo VirtualPath di questa direttiva indica il file della pagina master. Il compilatore può quindi riconoscere i campi, le proprietà e i metodi pubblici esposti dalla classe della pagina master, in questo caso di tipo [MasterPage].
- righe 5-22: il contenuto che verrà inserito nel contenitore [ContentPlaceHolder1] della pagina master.
Sarà possibile costruire questa pagina inserendo come contenuto (righe 6-21) quello della vista [VueSaisies] descritta al paragrafo 8.5.3 e quello della vista [VueSimulation] descritta al paragrafo 8.5.4.
11.4.3. La pagina [Simulations.aspx]
Per generare questa pagina, si seguirà il metodo illustrato al paragrafo 11.4.1 e si rinominerà [Simulations.aspx] la pagina [WebForm1.aspx] così generata. L'aspetto visivo della pagina [Simulations.aspx] in fase di costruzione è il seguente:
![]() |
L'aspetto visivo della pagina [Simulations.aspx] presenta due elementi:
- in [1] la pagina master con il suo contenitore [ContentPlaceHolder1]
- in [2] i componenti inseriti nel contenitore [ContentPlaceHolder1]. Questi sono identici a quelli dell'applicazione precedente.
Il codice sorgente di questa pagina è il seguente:
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
CodeBehind="Simulations.aspx.cs" Inherits="pam_v7.PageSimulations" Title="Pam : liste des simulations" %>
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" runat="Server">
<asp:MultiView ID="MultiView1" runat="server">
<asp:View ID="View1" runat="server">
<h2>
Liste de vos simulations</h2>
<p>
<asp:GridView ID="GridViewSimulations" runat="server" ...>
...
</asp:GridView>
</p>
</asp:View>
<asp:View ID="View2" runat="server">
<h2>
La liste de vos simulations est vide</h2>
</asp:View>
</asp:MultiView><br />
</asp:Content>
È possibile creare questa pagina inserendo come contenuto (righe 5-21) quello della vista [VueSimulations] descritta al paragrafo 8.5.5 e quello della vista [VueSimulationsVides] descritta al paragrafo 8.5.6.
11.4.4. La pagina [Erreurs.aspx]
Per generare questa pagina, si seguirà il metodo illustrato al paragrafo 11.4.1 e si rinominerà [Erreurs.aspx] la pagina [WebForm1.aspx] così generata. L'aspetto visivo della pagina [Erreurs.aspx] in fase di costruzione è il seguente:
![]() |
L'aspetto visivo della pagina [Erreurs.aspx] presenta due elementi:
- in [1] la pagina master con il suo contenitore [ContentPlaceHolder1]
- in [2] i componenti inseriti nel contenitore [ContentPlaceHolder1]. Questi sono identici a quelli dell'applicazione precedente.
Il codice sorgente di questa pagina è il seguente:
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
CodeBehind="Erreurs.aspx.cs" Inherits="pam_v7.PageErreurs" Title="Pam : erreurs" %>
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<h3>Les erreurs suivantes se sont produites au démarrage de l'application</h3>
<ul>
<asp:Repeater id="rptErreurs" runat="server">
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</asp:Content>
11.5. Il codice di controllo delle pagine
11.5.1. Panoramica
Torniamo all'architettura dell'applicazione:
![]() |
- [Global] è l'oggetto di tipo [HttpApplication] che inizializza (fase 0) l'applicazione. Questa classe è identica a quella della versione precedente.
- Il codice del controller, che nella versione precedente era interamente contenuto in [Default.aspx.cs], è ora distribuito su più pagine:
- [MasterPage.master]: la pagina principale delle pagine [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Contiene il menu.
- [Formulaire.aspx]: la pagina che presenta il modulo di simulazione e gestisce le azioni che avvengono su tale modulo
- [Simulations.aspx]: la pagina che presenta l'elenco delle simulazioni e gestisce le azioni che avvengono su questa stessa pagina
- [Erreurs.aspx]: la pagina visualizzata in caso di errore di inizializzazione dell’applicazione. Su questa pagina non sono possibili azioni.
L’elaborazione di una richiesta da parte di un cliente si svolge secondo le seguenti fasi:
- il cliente invia una richiesta all’applicazione. Normalmente la invia a una delle due pagine [Formulaire.aspx, Simulations.aspx], ma nulla gli impedisce di richiedere la pagina [Erreurs.aspx]. Occorrerà prevedere questo caso.
- la pagina richiesta elabora tale richiesta (fase 1). A tal fine, potrebbe aver bisogno dell’aiuto del livello [métier] (fase 2), che a sua volta potrebbe aver bisogno del livello [dao] se è necessario scambiare dati con il database. L’applicazione riceve una risposta dal livello [métier].
- In base a questa, sceglie (fase 3) la vista (= la risposta) da inviare al cliente e gli fornisce (fase 4) le informazioni (il modello) di cui ha bisogno. Abbiamo visto tre possibilità per generare questa risposta:
- la pagina (D) richiesta è anche la pagina (R) inviata in risposta. Costruire il modello della risposta (R) consiste quindi nell’assegnare ad alcuni componenti della pagina (D) il valore che devono avere nella risposta.
- la pagina (D) richiesta non è la pagina (R) inviata in risposta. La pagina (D) può quindi:
- trasferire il flusso di esecuzione alla pagina (R) tramite l’istruzione Server.Transfer(" R "). Il modello può quindi essere inserito nel contesto tramite Context.Items("chiave")=valore o, più raramente, nella sessione tramite Session.Items("chiave")=valore
- reindirizzare il cliente alla pagina (R) tramite l’istruzione Response.redirect(" R "). Il modello può quindi essere inserito nella sessione ma non nel contesto.
- la risposta viene inviata al cliente (fase 5)
Ciascuna delle pagine [MasterPage.master, Formulaire.aspx, Simulations.aspx, Erreurs.aspx] risponderà a uno o più degli eventi riportati di seguito:
- Init: primo evento nel ciclo di vita della pagina
- Load: si verifica al caricamento della pagina
- Click: clic su uno dei link del menu della pagina principale
Elaboriamo le pagine una dopo l’altra, iniziando dalla pagina principale.
11.5.2. Codice di controllo della pagina [MasterPage.master]
11.5.2.1. Struttura della classe
Il codice di controllo della pagina master presenta la seguente struttura:
using System.Web.UI.WebControls;
namespace pam_v7
{
public partial class MasterPage : System.Web.UI.MasterPage
{
// il menu
public LinkButton OptionFaireSimulation
{
get { return LinkButtonFaireSimulation; }
}
...
// si corregge il menu
public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
{
....
}
// gestione dell'opzione [Terminer la session]
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
....
}
// inizializza la pagina principale
protected void Page_Init(object sender, System.EventArgs e)
{
....
}
}
}
}
- riga 5: la classe si chiama [MasterPage] e deriva dalla classe di sistema [System.Web.UI.MasterPage].
- righe 9-14: le 6 opzioni del menu sono definite come proprietà pubbliche della classe
- righe 16-19: il metodo pubblico SetMenu consentirà alle pagine [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] di impostare il menu della pagina master
- righe 22-25: la procedura che gestirà il clic sul link [LinkButtonTerminerSession]
- righe 28-31: la procedura di gestione dell'evento Init della pagina master
11.5.2.2. Proprietà pubbliche della classe
using System.Web.UI.WebControls;
namespace pam_v7
{
public partial class MasterPage : System.Web.UI.MasterPage
{
// il menu
public LinkButton OptionFaireSimulation
{
get { return LinkButtonFaireSimulation; }
}
public LinkButton OptionEffacerSimulation
{
get { return LinkButtonEffacerSimulation; }
}
public LinkButton OptionEnregistrerSimulation
{
get { return LinkButtonEnregistrerSimulation; }
}
public LinkButton OptionVoirSimulations
{
get { return LinkButtonVoirSimulations; }
}
public LinkButton OptionTerminerSession
{
get { return LinkButtonTerminerSession; }
}
public LinkButton OptionFormulaireSimulation
{
get { return LinkButtonFormulaireSimulation; }
}
...
}
}
Per comprendere questo codice, è necessario ricordare i componenti che costituiscono la pagina master:
![]() |
N. | Tipo | Nome | Ruolo |
Pannello (rosa sopra) | intestazione | intestazione della pagina | |
Pannello (giallo sopra) | contenuto | contenuto della pagina | |
LinkButton | LinkButtonFaireSimulation | richiede il calcolo della simulazione | |
LinkButton | LinkButtonEffacerSimulation | cancella il modulo di inserimento dati | |
LinkButton | LinkButtonVoirSimulations | visualizza l'elenco delle simulazioni già effettuate | |
LinkButton | LinkButtonFormulaireSimulation | torna al modulo di inserimento dati | |
LinkButton | LinkButtonEnregistrerSimulation | salva la simulazione corrente nell'elenco delle simulazioni | |
LinkButton | LinkButtonTerminerSession | chiude la sessione corrente |
I componenti da 1 a 6 non sono accessibili al di fuori della pagina che li contiene. Le proprietà delle righe da 9 a 37 hanno lo scopo di renderli accessibili alle classi esterne, in questo caso alle classi delle altre pagine dell'applicazione.
11.5.2.3. Il metodo SetMenu
Il metodo pubblico SetMenu consente alle pagine [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] di impostare il menu della pagina principale. Il suo codice è semplice:
// fissare il menu
public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
{
// impostazione delle opzioni del menu
LinkButtonFaireSimulation.Visible = boolFaireSimulation;
LinkButtonEnregistrerSimulation.Visible = boolEnregistrerSimulation;
LinkButtonEffacerSimulation.Visible = boolEffacerSimulation;
LinkButtonVoirSimulations.Visible = boolVoirSimulations;
LinkButtonFormulaireSimulation.Visible = boolFormulaireSimulation;
LinkButtonTerminerSession.Visible = boolTerminerSession;
}
11.5.2.4. La gestione degli eventi della pagina master
La pagina master gestirà due eventi:
- l'evento Init, che è il primo evento del ciclo di vita della pagina
- l'evento Click relativo al link [LinkButtonTerminerSession]
La pagina master presenta altri cinque link: [LinkButtonFaireSimulation, LinkButtonEnregistrerSimulation, LinkButtonEffacerSimulation, LinkButtonVoirSimulations, LinkButtonFormulaireSimulation]. A titolo di esempio, esaminiamo cosa occorre fare quando si clicca sul link [LinkButtonFaireSimulation]:
- verificare i dati inseriti (ore, giorni) nella pagina [Formulaire.aspx]
- effettuare il calcolo dello stipendio
- visualizzare i risultati nella pagina [Formulaire.aspx]
Le operazioni 1 e 3 richiedono l’accesso ai componenti della pagina [Formulaire.aspx]. Ma non è così. Infatti, la pagina principale non ha alcuna conoscenza dei componenti delle pagine che potrebbero essere inserite nel suo contenitore [ContentPlaceHolder1]. Nel nostro esempio, spetta alla pagina [Formulaire.aspx] gestire il clic sul link [LinkButtonFaireSimulation], poiché è proprio quella la pagina visualizzata quando si verifica tale evento. Come può esserne informata?
- Poiché il link [LinkButtonFaireSimulation] non fa parte della pagina [Formulaire.aspx], non è possibile scrivere nella pagina [Formulaire.aspx] la procedura usuale:
private void LinkButtonFaireSimulation_Click(object sender, System.EventArgs e)
{
...
}
È possibile aggirare il problema con il seguente codice in [Formulaire.aspx]:
using System.Collections.Generic;
...
namespace pam_v7
{
public partial class Formulaire : System.Web.UI.Page
{
// caricamento della pagina
protected void Page_Load(object sender, System.EventArgs e)
{
// gestore eventi
Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
...
}
// calcolo delle retribuzioni
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
....
}
// cancella la simulazione
private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
{
...
}
protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
{
...
}
protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
{
...
}
}
}
- righe 12-15: quando si verifica l'evento Load della pagina [Formulaire.aspx], la classe [MasterPage] della pagina master è stata istanziata. Le sue proprietà pubbliche Optionxx sono accessibili e sono di tipo LinkButton, un componente che supporta l'evento Click. A questi eventi Click associamo i metodi:
- OptFaireSimulation_Click per l’evento Click sul collegamento LinkButtonFaireSimulation
- OptEffacerSimulation_Click per l'evento Click sul collegamento LinkButtonEffacerSimulation
- OptVoirSimulations_Click per l'evento Click sul link LinkButtonVoirSimulations
- OptEnregistrerSimulation_Click per l'evento Click sul link LinkButtonEnregistrerSimulation
La gestione degli eventi Click sui sei link del menu sarà ripartita come segue:
- la pagina [Formulaire.aspx] gestirà i link [LinkButtonFaireSimulation, LinkButtonEnregistrerSimulation, LinkButtonEffacerSimulation, LinkButtonVoirSimulations]
- la pagina [Simulations.aspx] gestirà il link [LinkButtonFormulaireSimulation]
- la pagina master [MasterPage.master] gestirà il collegamento [LinkButtonTerminerSession]. Per questo evento, infatti, non ha bisogno di conoscere la pagina che incapsula.
11.5.2.5. L’evento Init della pagina principale
Le tre pagine [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] dell’applicazione hanno come pagina master [MasterPage.master]. Indichiamo con M la pagina master e con E la pagina incapsulata. Quando la pagina E viene richiesta dal client, si verificano i seguenti eventi in ordine:
- E.Init
- M.Init
- E.Load
- M.Load
- ...
Utilizzeremo l'evento Init della pagina M per eseguire del codice che sarebbe opportuno eseguire il prima possibile, indipendentemente dalla pagina di destinazione E. Per individuare questo codice, rivediamo la panoramica dell'applicazione:
![]() |
Nell’immagine sopra, [Global] è l’oggetto di tipo [HttpApplication] che inizializza l’applicazione. Questa classe è la stessa della versione [pam-v4-3tier-nhibernate-multivues-monopage]:
using System;
...
namespace pam_v7
{
public class Global : System.Web.HttpApplication
{
// --- dati statici dell'applicazione ---
public static Employe[] Employes;
public static IPamMetier PamMetier = null;
public static string Msg;
public static bool Erreur = false;
// avvio dell'applicazione
public void Application_Start(object sender, EventArgs e)
{
...
}
public void Session_Start(object sender, EventArgs e)
{
...
}
}
}
Se la classe [Global] non riesce a inizializzare correttamente l’applicazione, imposta due variabili pubbliche statiche:
- il valore booleano Errore alla riga 12 viene impostato su vrai
- la variabile Msg della riga 11 contiene un messaggio che fornisce dettagli sull'errore riscontrato
Quando l’utente richiede una delle pagine [Formulaire.aspx, Simulations.aspx] mentre l’applicazione non si è inizializzata correttamente, tale richiesta deve essere trasferita o reindirizzata alla pagina [Erreurs.aspx], che visualizzerà il messaggio di errore della classe [Global]. È possibile gestire questo caso in vari modi:
- eseguire il controllo degli errori di inizializzazione nel gestore degli eventi Init o Load di ciascuna delle pagine [Formulaire.aspx, Simulations.aspx]
- eseguire il test di errore di inizializzazione nel gestore degli eventi Init o Load della pagina master di queste due pagine. Questo metodo presenta il vantaggio di collocare il test di errore di inizializzazione in un unico punto.
Abbiamo scelto di eseguire il test di errore di inizializzazione nel gestore dell'evento Init della pagina master:
protected void Page_Init(object sender, System.EventArgs e)
{
// gestore eventi
LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
// Errori di inizializzazione?
if (Global.Erreur)
{
// la pagina incapsulata è la pagina degli errori?
bool isPageErreurs =...;
// se viene visualizzata la pagina degli errori, si lascia procedere; altrimenti si reindirizza il client alla pagina degli errori
if (!isPageErreurs)
Response.Redirect("Erreurs.aspx");
return;
}
}
Il codice sopra riportato verrà eseguito non appena verrà richiesta una delle pagine [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Nel caso in cui la pagina richiesta sia [Formulaire.aspx, Simulations.aspx], ci limitiamo (riga 12) a reindirizzare il client alla pagina [Erreurs.aspx], che si occuperà di visualizzare il messaggio di errore della classe [Global]. Nel caso in cui la pagina richiesta sia [Erreurs.aspx], tale reindirizzamento non deve avvenire: occorre lasciare che venga visualizzata la pagina [Erreurs.aspx]. Dobbiamo quindi sapere, nel metodo [Page_Init] della pagina master, quale sia la pagina che essa incapsula.
Torniamo all’albero dei componenti della pagina principale:
...
<body background="ressources/standard.jpg">
<form id="form1" runat="server">
<asp:Panel ID="entete" runat="server" BackColor="#FFE0C0" Width="1239px" >
...
</asp:Panel>
<div>
<asp:Panel ID="contenu" runat="server" BackColor="#FFFFC0">
<asp:ContentPlaceHolder ID="ContentPlaceHolder1" runat="server">
</asp:ContentPlaceHolder>
</asp:Panel>
</div>
</form>
</body>
</html>
- righe 1-13: il contenitore con id "form1"
- righe 4-6: il contenitore con id "entete", incluso nel contenitore con id "form1"
- righe 8-11: il contenitore con id "contenu", incluso nel contenitore con id "form1"
- righe 9-10: il contenitore con id "ContentPlaceHolder1", incluso nel contenitore con id "contenuto"
Una pagina E incapsulata nella pagina master M si trova all’interno del contenitore con ID "ContentPlaceHolder1". Per fare riferimento a un componente con ID C di questa pagina E, si scriverà:
this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("C");
L'albero dei componenti della pagina [Erreurs.aspx] è il seguente:
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
CodeBehind="Erreurs.aspx.cs" Inherits="pam_v7.PageErreurs" Title="Pam : erreurs" %>
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<h3>Les erreurs suivantes se sont produites au démarrage de l'application</h3>
<ul>
<asp:Repeater id="rptErreurs" runat="server">
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</asp:Content>
Quando la pagina [Erreurs.aspx] viene unita alla pagina master M, il contenuto del tag <asp:Content> sopra riportato (righe 5-16) viene integrato nel tag <asp:ContentPlaceHolder> con id "ContentPlaceholder1" della pagina M, il cui albero dei componenti diventa quindi:
- riga 12: il componente [rptErreurs] può essere utilizzato per verificare se la pagina master M contenga o meno la pagina [Erreurs.aspx]. Infatti, questo componente esiste solo in questa pagina.
Queste spiegazioni sono sufficienti per comprendere il codice della procedura [Page_Init] della pagina master:
protected void Page_Init(object sender, System.EventArgs e)
{
// gestore eventi
LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
// errori di inizializzazione?
if (Global.Erreur)
{
// la pagina incapsulata è la pagina degli errori?
bool isPageErreurs = this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("rptErreurs") != null;
// se viene visualizzata la pagina degli errori, si lascia fare; altrimenti si reindirizza il client alla pagina degli errori
if (!isPageErreurs)
Response.Redirect("Erreurs.aspx");
return;
}
}
- riga 4: si associa un gestore di eventi all’evento Click sul collegamento LinkButtonTerminerSession. Questo gestore si trova nella classe MasterPage.
- riga 6: si verifica se la classe [Global] ha impostato il proprio valore booleano Erreur
- riga 9: in caso affermativo, il valore booleano IsPageErreurs indica se la pagina incapsulata nella pagina master è la pagina [Erreurs.aspx]
- riga 12: se la pagina incapsulata nella pagina master non è la pagina [Erreurs.aspx], allora si reindirizza il client a tale pagina, altrimenti non si fa nulla.
11.5.2.6. L'evento Click sul link [LinkButtonTerminerSession]
![]() |
Quando l'utente clicca sul link [Terminer la session] nella vista (1) sopra riportata, è necessario svuotare il contenuto della sessione e presentare un modulo vuoto (2).
Il codice del gestore di questo evento potrebbe essere il seguente:
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
// si interrompe la sessione
Session.Abandon();
// si visualizza la vista [formulaire]
Response.Redirect("Formulaire.aspx");
}
- riga 4: la sessione corrente viene interrotta
- riga 6: il cliente viene reindirizzato alla pagina [Formulaire.aspx]
Si nota che questo codice non coinvolge nessuno dei componenti delle pagine [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. L’evento può quindi essere gestito dalla pagina principale stessa.
11.5.3. Codice di controllo della pagina [Erreurs.aspx]
Il codice di controllo della pagina [Erreurs.aspx] potrebbe essere il seguente:
using System.Collections.Generic;
namespace pam_v7
{
public partial class Erreurs : System.Web.UI.Page
{
protected void Page_Load(object sender, System.EventArgs e)
{
// Errori di inizializzazione?
if (Global.Erreur)
{
// si prepara il modello della pagina [erreurs]
List<string> erreursInitialisation = new List<string>();
erreursInitialisation.Add(Global.Msg);
// si associa l'elenco degli errori al relativo componente
rptErreurs.DataSource = erreursInitialisation;
rptErreurs.DataBind();
}
// si imposta il menu
Master.SetMenu(false, false, false, false, false, false);
}
}
}
Ricordiamo che l’unica funzione della pagina [Erreurs.aspx] è quella di visualizzare un errore di inizializzazione dell’applicazione quando questo si verifica:
- riga 10: si verifica se l’inizializzazione si è conclusa con un errore
- righe 13-14: in caso affermativo, il messaggio di errore (Global.Msg) viene inserito in un elenco [ErreursInitialisation]
- righe 16-17: si richiede al componente [rptErreurs] di visualizzare tale elenco
- riga 20: in ogni caso (errore o meno), le opzioni del menu della pagina principale non vengono visualizzate, in modo che l'utente non possa avviare alcuna nuova azione da questa pagina.
Cosa succede se l’utente richiede direttamente la pagina [Erreurs.aspx] (cosa che non dovrebbe fare durante il normale utilizzo dell’applicazione)? Analizzando il codice di [MasterPage.master.cs] e di [Erreurs.aspx.cs], si noterà che:
- se si è verificato un errore di inizializzazione, questo viene visualizzato
- se non si è verificato alcun errore di inizializzazione, all’utente viene visualizzata una pagina contenente solo l’intestazione di [MasterPage.master] senza alcuna opzione di menu visualizzata.
11.5.4. Codice di controllo della pagina [Formulaire.aspx]
11.5.4.1. Struttura della classe
Lo scheletro del codice di controllo della pagina [Formulaire.aspx] potrebbe essere il seguente:
using Pam.Metier.Entites;
...
partial class PageFormulaire : System.Web.UI.Page
{
// caricamento della pagina
protected void Page_Load(object sender, System.EventArgs e)
{
// gestore eventi
Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
....
}
// calcolo delle retribuzioni
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
....
}
// cancella la simulazione
private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
{
...
}
protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
{
....
}
protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
{
...
}
}
Il codice di controllo della pagina [Formulaire.aspx] gestisce cinque eventi:
- l’evento Load della pagina
- l'evento Click sul link [LinkButtonFaireSimulation] della pagina master
- l'evento Click sul collegamento [LinkButtonEffacerSimulation] della pagina principale
- l'evento Click sul link [LinkButtonEnregistrerSimulation] della pagina principale
- l'evento Click sul collegamento [LinkButtonVoirSimulations] della pagina principale
11.5.4.2. Evento Load della pagina
Lo scheletro del gestore dell'evento Load della pagina potrebbe essere il seguente:
protected void Page_Load(object sender, System.EventArgs e)
{
// gestione eventi
Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
// Visualizzazione vista [saisies]
...
// Posizionamento menu pagina master
...
// elaborazione richiesta GET
if (!IsPostBack)
{
// caricamento dei nomi dei dipendenti nel menu a tendina
...
// inizializzazione della vista [saisies] con i dati inseriti memorizzati nella sessione, se presenti
....
}
}
Un esempio per chiarire il commento della riga 17 potrebbe essere questo:
![]() |
![]() |
- in [1], si richiede di visualizzare l’elenco delle simulazioni. Sono stati effettuati inserimenti in [A, B, C].
- in [2], si visualizza l’elenco
- in [3], si richiede di tornare al modulo
- in [4], si ritrova il modulo così come lo si era lasciato. Poiché ci sono state due richieste, (1,2) e (3,4), ciò significa che:
- durante il passaggio da [1] a [2], i dati inseriti in [1] sono stati memorizzati
- durante il passaggio da [3] a [4], sono stati ripristinati. È la procedura [Page_Load] di [Formulaire.aspx] che esegue tale ripristino.
Domanda: completare la procedura Page_Load avvalendosi dei commenti e del codice della versione [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.4.3. Gestione degli eventi «Clic» sui link del menu
Lo scheletro dei gestori degli eventi Click relativi ai link della pagina principale è il seguente:
// calcolo della busta paga
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
// effetto Ajax
Thread.Sleep(3000);
// pagina valida?
Page.Validate();
if (!Page.IsValid)
{
// visualizzazione della vista [saisie]
...
}
// la pagina è valida - si recuperano i dati inseriti
...
// si calcola lo stipendio del dipendente
FeuilleSalaire feuillesalaire;
try
{
feuillesalaire = ...;
}
catch (PamException ex)
{
// si è verificato un problema
...
return;
}
// si inserisce il risultato nella sessione
Session["simulation"] = ...;
// si salvano i dati inseriti nella sessione
...
// visualizzazione
...
// visualizzazione delle viste
...
// visualizzazione del menu MasterPage
...
}
// cancella la simulazione
private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
{
// visualizzazione pannello [saisie]
...
// selezione primo dipendente
...
}
protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
{
// si inseriscono i dati nella sessione
...
// visualizza la vista [simulations]
Response.Redirect("simulations.aspx");
}
protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
{
// si salva la simulazione corrente nella sessione dell'utente
...
// si visualizza la vista [simulations]
Response.Redirect("simulations.aspx");
}
Domanda: completare il codice delle procedure sopra riportate avvalendosi dei commenti e del codice della versione [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.5. Codice di controllo della pagina [Simulations.aspx]
Lo scheletro del codice di controllo della pagina [Simulations.aspx] potrebbe essere il seguente:
using System.Collections.Generic;
using Pam.Web;
using System.Web.UI.WebControls;
partial class PageSimulations : System.Web.UI.Page
{
// le simulazioni
private List<Simulation> simulations;
// caricamento della pagina
protected void Page_Load(object sender, System.EventArgs e)
{
// gestore eventi
Master.OptionFormulaireSimulation.Click += OptFormulaireSimulation_Click;
GridViewSimulations.RowDeleting += GridViewSimulations_RowDeleting;
// si recuperano le simulazioni nella sessione
simulations = ...;
// ci sono simulazioni?
if (simulations.Count != 0)
{
// prima vista visibile
...
// si popola la griglia
...
}
else
{
// seconda vista
...
}
// si fissa il menu
...
}
protected void GridViewSimulations_RowDeleting(object sender, System.Web.UI.WebControls.GridViewDeleteEventArgs e)
{
// si recuperano le simulazioni nella sessione
List<Simulation> simulations = ...;
// si elimina la simulazione indicata (e.RowIndex rappresenta il numero della riga eliminata nella GridView)
..
// rimangono delle simulazioni?
if (simulations.Count != 0)
{
// si compila la griglia
...
}
else
{
// vista [SimulationsVides]
...
}
}
protected void OptFormulaireSimulation_Click(object sender, System.EventArgs e)
{
// si visualizza la vista [formulaire]
Response.Redirect("formulaire.aspx");
}
}
Domanda: completare il codice delle procedure sopra riportate avvalendosi dei commenti e del codice della versione [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.6. Codice di controllo della pagina [Default.aspx]
È possibile prevedere una pagina [Default.aspx] nell’applicazione, per consentire all’utente di richiedere l’URL dell’applicazione senza specificare una pagina, come di seguito:
![]() |
La richiesta [1] ha ricevuto in risposta la pagina [Formulaire.aspx] (2). Si sa che la richiesta (1) viene gestita per impostazione predefinita dalla pagina [Default.aspx] dell'applicazione. Per ottenere (2), è sufficiente che [Default.aspx] reindirizzi il client alla pagina [Formulaire.aspx]. Ciò può essere ottenuto con il seguente codice:
partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, System.EventArgs e)
{
// si reindirizza al modulo di inserimento
Response.Redirect("Formulaire.aspx");
}
}
La pagina di presentazione [Default.aspx] contiene invece solo la direttiva che la collega a [Default.aspx.cs]:
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="pam_v7._Default" Title="Untitled Page" %>

























