11. La aplicación [SimuPaie] – version 7 – ASP.NET / vistas múltiples / páginas múltiples
Lecturas recomendadas: referencia [1], Desarrollo WEB con ASP.NET 1.1 párrafo: Ejemplos
Ahora estudiamos una version funcionalmente idéntica a la aplicación ASP.NET de tres capas [pam-v4-3tier-nhibernate-multivues-monopage] estudiada anteriormente, pero modificamos la arquitectura de esta última de la siguiente manera: mientras que en la anterior version las vistas se implementaban mediante una única página ASPX, aquí se implementarán mediante tres páginas ASPX.
La arquitectura de la aplicación anterior era la siguiente:
![]() |
Aquí tenemos una arquitectura MVC (Modelo – Vista – Controlador):
- [Default.aspx.cs] contiene el código del controlador. La página [Default.aspx] es el único interlocutor del cliente. Por ella pasan todas las solicitudes de este.
- [Saisies, Simulation, Simulations, ...] son las vistas. Estas vistas se implementan aquí mediante componentes [View] de la página [Default.aspx].
La arquitectura de la nueva version será la siguiente:
![]() |
- solo cambia la capa [web]
- las vistas (lo que se muestra al usuario) no cambian.
- El código del controlador, que en la versión anterior version se encontraba íntegramente en [Default.aspx.cs], ahora se distribuye en varias páginas:
- [MasterPage.master]: una página que agrupa lo que es común a las diferentes vistas: la barra superior con sus opciones de menú
- [Formulaire.aspx]: la página que presenta el formulario de simulación y gestiona las acciones que tienen lugar en dicho formulario
- [Simulations.aspx]: la página que muestra la lista de simulaciones y gestiona las acciones que tienen lugar en esta misma página
- [Erreurs.aspx]: la página que se muestra cuando se produce un error de inicialización de la aplicación. No hay acciones posibles en esta página.
Se puede considerar que aquí tenemos una arquitectura MVC con múltiples controladores, mientras que la arquitectura de la anterior version era una arquitectura MVC con un único controlador.
El procesamiento de una solicitud de un cliente se lleva a cabo siguiendo los siguientes pasos:
- el cliente realiza una solicitud a la aplicación. La realiza a una de las dos páginas [Formulaire.aspx, Simulations.aspx].
- La página solicitada procesa esta solicitud. Para ello, puede necesitar la ayuda de la capa [métier], que a su vez puede necesitar la capa [dao] si es necesario intercambiar datos con la base de datos. La aplicación recibe una respuesta de la capa [métier].
- En función de esta, elige (3) la vista (= la respuesta) que se enviará al cliente, proporcionándole (4) la información (el modelo) que necesita.
- La respuesta se envía al cliente (5)
11.1. Las vistas de la aplicación
Las diferentes vistas que se muestran al usuario son las siguientes:
- - la vista [VueSaisies], que muestra el formulario de simulación
![]() |
- - la vista [VueSimulation], utilizada para mostrar el resultado detallado de la simulación:
![]() |
- - la vista [VueSimulations], que muestra la lista de simulaciones realizadas por el cliente
![]() |
- - la vista [VueSimulationsVides], que indica que el cliente no tiene simulaciones o ya no las tiene:
![]() |
- la vista [VueErreurs], que indica un error de inicialización de la aplicación:
![]() |
11.2. Generación de vistas en un contexto multicontrolador
En la vista version anterior, todas las vistas se generaban a partir de la única página [Default.aspx]. Esta contenía dos componentes [MultiView] y las vistas se componían de una combinación de uno o dos componentes [View] pertenecientes a estos dos componentes [MultiView].
Eficaz cuando hay pocas vistas, esta arquitectura alcanza sus límites en cuanto el número de componentes que forman las diferentes vistas se vuelve importante: de hecho, con cada solicitud que se realiza a la única página [Default.aspx], se instancian todos los componentes de la misma, cuando en realidad solo algunos de ellos se utilizarán para generar la respuesta al usuario. Así, se realiza un trabajo innecesario con cada nueva solicitud, trabajo que resulta penalizador cuando el número total de componentes de la página es elevado.
Una solución es, por tanto, distribuir las vistas en diferentes páginas. Eso es lo que hacemos aquí. Analicemos dos casos diferentes de generación de vistas:
- la solicitud se realiza a una página P1 y esta genera la respuesta
- la solicitud se realiza a una página P1 y esta solicita a una página P2 que genere la respuesta
11.2.1. Caso 1: una página controlador/vista
En el caso 1, volvemos a la arquitectura de controlador único de la version anterior, donde la página [Default.aspx] es la página P1:
![]() |
- el cliente realiza una solicitud a la página P1 (1)
- la página P1 procesa esta solicitud. Para ello, puede necesitar la ayuda de la capa [métier] (2), que a su vez puede necesitar la capa [dao] si es necesario intercambiar datos con la base de datos. La aplicación recibe una respuesta de la capa [métier].
- En función de esta, elige (3) la vista (= la respuesta) que se enviará al cliente, proporcionándole (4) la información (la plantilla) que necesita. Se trata, en este caso, de seleccionar en la página P1 los componentes [Panel] o [View] que se van a mostrar e inicializar los componentes que contienen.
- La respuesta se envía al cliente (5)
A continuación se muestran dos ejemplos extraídos de la aplicación estudiada:
[page Formulaire.aspx]
![]() |
- en [1]: el usuario, tras haber solicitado la página [Formulaire.aspx], solicita una simulación
- en [2]: la página [Formulaire.aspx] ha procesado esta solicitud y ha generado ella misma la respuesta mostrando un componente [View] que no se había mostrado en [1]
[page Simulations.aspx]
![]() |
- en [1]: el usuario, tras solicitar la página [Simulations.aspx], desea eliminar una simulación
- en [2]: la página [Simulations.aspx] ha procesado esta solicitud y ha generado ella misma la respuesta volviendo a mostrar la nueva lista de simulaciones.
![]() |
11.2.2. Caso 2: una página 1 controlador, una página 2 controlador / vista
El caso 2 puede abarcar diversas arquitecturas. Elegiremos la siguiente:
![]() |
- el cliente realiza una solicitud a la página P1 (1)
- la página P1 procesa esta solicitud. Para ello, puede necesitar la ayuda de la capa [métier] (2), que a su vez puede necesitar la capa [dao] si es necesario intercambiar datos con la base de datos. La aplicación recibe una respuesta de la capa [métier].
- En función de esta, elige (3) la vista (= la respuesta) que se enviará al cliente, proporcionándole (4) la información (el modelo) que necesita. Resulta que, en este caso, la vista debe generarse mediante una página distinta de P1, concretamente la página P2. Para realizar las operaciones (3) y (4), la página P1 tiene dos posibilidades:
- Realizar una transferencia de ejecución a la página P2 mediante la operación [Server.Transfer(" P2.aspx ")]. En este caso, puede colocar la plantilla destinada a la página P2 en el contexto de la solicitud [Context.Items[" clé "]=valeur] o en la sesión del usuario [Session.[" clé "]=valeur]. La página P2 se instanciará entonces y, durante el procesamiento de su evento Load, por ejemplo, podrá recuperar la información transmitida por la página P1 mediante las operaciones [valeur=(Type)Context.Items[" clé "]] o bien [valeur=(Type)Session[" clé "]], según el caso, donde Tipo es el tipo del valor asociado a la clave. La transmisión de valores a través del contexto Context es la más adecuada si no es necesario conservar los valores del modelo para una futura solicitud del cliente.
- solicitar al cliente que se redirija a la página P2 mediante la operación [Response.Redirect(" P2.aspx ")]. En este caso, la página P1 colocará el modelo destinado a la página P2 en la sesión, ya que el contexto de solicitud Context se elimina al final de cada solicitud. Sin embargo, en este caso, la redirección provocará el fin de la primera solicitud del cliente a P1 y el envío de una segunda solicitud de ese mismo cliente, esta vez a P2. Hay dos solicitudes sucesivas. Sabemos que la sesión es uno de los medios para conservar la «memoria» entre solicitudes. Existen otras soluciones además de la sesión.
- Sea cual sea la forma en que P2 toma el control, volvemos al caso 1: P2 ha recibido una solicitud que va a procesar (5) y generará ella misma la respuesta (6, 7). También se puede imaginar que la página P2, tras procesar la solicitud, ceda el control a una página P3, y así sucesivamente.
He aquí un ejemplo extraído de la aplicación estudiada:
![]() |
- en [1]: el usuario que ha solicitado la página [Formulaire.aspx] pide ver la lista de simulaciones
- en [2]: la página [Formulaire.aspx] procesa esta solicitud y redirige al cliente a la página [Simulations.aspx]. Es esta última la que proporciona la respuesta al usuario. En lugar de pedir al cliente que se redirija, la página [Formulaire.aspx] podría haber transferido la solicitud del cliente a la página [Simulations.aspx]. En este caso, en [2] se habría visto la misma Url que en [1]. De hecho, un navegador siempre muestra la última Url solicitada:
- la acción solicitada en [1] está destinada a la página [Formulaire.aspx]. El navegador realiza un POST hacia esta página.
- Si la página [Formulaire.aspx] procesa la solicitud y luego la transfiere mediante [Server.Transfer(" Simulations.aspx ")] a la página [Simulations.aspx], se mantiene la misma solicitud. El navegador mostrará entonces en [2], el URL de [Formulaire.aspx] hacia el que se realizó el POST.
- Si la página [Formulaire.aspx] procesa la solicitud y luego la redirige a través de [Response.Redirect(" Simulations.aspx ")] hacia la página [Simulations.aspx], el navegador realiza entonces una segunda solicitud, un GET hacia [Simulations.aspx]. El navegador mostrará entonces en [2] el URL de [Simulations.aspx] hacia el que se dirigió el GET. Esto es lo que nos muestra la captura de pantalla [2] anterior.
11.3. El proyecto Visual Web Developer de la capa [web]
El proyecto Visual Web Developer de la capa [web] es el siguiente:
![]() |
- en [1] encontramos:
- el archivo de configuración [Web.config] de la aplicación – es idéntico al de la aplicación [pam-v4-3tier-nhibernate-multivues-monopage].
- la página [Default.aspx] – se limita a redirigir al cliente a la página [Formulaire.aspx]
- la página [Formulaire.aspx], que muestra al usuario el formulario de simulación y gestiona las acciones relacionadas con dicho formulario
- la página [Simulations.aspx], que muestra al usuario la lista de sus simulaciones y gestiona las acciones relacionadas con esta página
- la página [Erreurs.aspx], que muestra al usuario una página que indica un error detectado al iniciar la aplicación web.
- En [2] se ven las referencias del proyecto.
Volvamos a la arquitectura del nuevo proyecto:
![]() |
En comparación con el proyecto [pam-v4-3tier-nhibernate-multivues-monopage], solo cambian las vistas. Así, el nuevo proyecto retoma algunos de los archivos de este proyecto:
- el archivo de configuración [Web.config]
- los DLL referenciados por [pam-dao-nhibernate, pam-metier-dao-nhibernate, Spring.Core, NHibernate]
- la clase global de aplicación [Global.asax]
- las carpetas [images, ressources, pam]
Para mantener la coherencia con el proyecto en desarrollo, nos aseguraremos de que el espacio de nombres de las vistas y de la clase global de aplicación sea [pam-v7]:
![]() |
11.4. El código de presentación de las páginas
11.4.1. La página maestra [MasterPage.master]
Las vistas de la aplicación presentadas en el apartado 11.1 tienen partes comunes que se pueden factorizar en una página maestra, denominada Master Page en Visual Studio. Tomemos, por ejemplo, las vistas [VueSaisies] y [VueSimulationsVides] que se muestran a continuación, generadas respectivamente por las páginas [Formulaire.aspx] y [Simulations.aspx]:
![]() |
Estas dos vistas tienen en común la barra superior (Título y Opciones de menú). Lo mismo ocurre con todas las vistas que se mostrarán al usuario: todas tendrán la misma barra superior. Para que diferentes páginas compartan un mismo fragmento de presentación, existen diversas soluciones, entre las que se incluyen las siguientes:
- colocar este fragmento común en un componente de usuario. Esta era la técnica principal con ASP.NET 1.1
- colocar este fragmento común en una página maestra. Esta técnica apareció con ASP.NET 2.0. Es la que utilizamos aquí.
Para crear una página maestra en una aplicación web, se puede proceder de la siguiente manera:
- clic con el botón derecho del ratón en el proyecto / Añadir un nuevo elemento / Página maestra:
![]() |
Al añadir una página maestra, se añaden por defecto tres archivos a la aplicación web:
- [MasterPage.master]: el código de presentación de la página maestra
- [MasterPage.master.cs]: el código de control de la página maestra
- [Masterpage.Master.designer.cs]: la declaración de los componentes de la página maestra
El código generado por Visual Studio en [MasterPage.master] es el siguiente:
<%@ 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>
- línea 1: la etiqueta <%@ Master ... %> sirve para definir la página como una página maestra. El código de control de la página estará en el archivo definido por el atributo CodeBehind, y la página heredará la clase definida por el atributo Inherits.
- líneas 12-18: el formulario de la página maestra
- líneas 14-16: un contenedor vacío que, en nuestra aplicación, contendrá una de las páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. El cliente recibe como respuesta, siempre la misma página, la página maestra, en la que el contenedor [ContentPlaceHolder1] recibirá un flujo HTML proporcionado por una de las páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Así, para cambiar el aspecto de las páginas enviadas a clients, basta con cambiar el aspecto de la página maestra.
- Líneas 8-9: un contenedor vacío con el que las páginas «hijas» podrán personalizar el encabezado <head>...</head>.
La representación visual (pestaña Diseño) de este código fuente se muestra en (1) a continuación. Además, es posible añadir tantos contenedores como se desee, gracias al componente [ContentPlaceHolder] (2) de la barra de herramientas [Standard].
![]() |
El código de control generado por Visual Studio en [MasterPage.master.cs] es el siguiente:
using System;
public partial class MasterPage : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
- línea 3: la clase a la que hace referencia el atributo [Inherits] de la directiva <%@ Master ... %> de la página [MasterPage.master] deriva de la clase [System.Web.UI.MasterPage]
Arriba vemos la presencia del método Page_Load que gestiona el evento Load de la página maestra. La página maestra contenerá en su interior otra página. ¿En qué orden se producen los eventos Load de las dos páginas? Se trata de una regla general: el evento Load de un componente se produce antes que el de su contenedor. En este caso, el evento Load de la página insertada en la página maestra tendrá lugar, por tanto, antes que el de la propia página maestra.
Para que e genere una página que tenga como página maestra la página [MasterPage.master] anterior, se puede proceder de la siguiente manera:
![]() |
- en [1]: clic con el botón derecho del ratón en la página maestra y, a continuación, option [Ajouter une page de contenu]
- en [2]: se genera una página por defecto, en este caso [WebForm1.aspx].
El código de presentación [WebForm1.aspx] es el siguiente:
<%@ 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>
- línea 1: la directiva Page y sus atributos
- MasterPageFile: designa el archivo de la página maestra de la página descrita por la directiva. El signo ~ designa la carpeta del proyecto.
- Los demás parámetros son los habituales de una página web ASP
- Líneas 2-3: las etiquetas <asp:Content> se vinculan una a una a las directivas <asp:ContentPlaceHolder> de la página maestra a través del atributo ContentPlaceHolderID. Los componentes situados entre las líneas 2-3 anteriores se colocarán, en el momento de la ejecución, en el contenedor de ID ContentPlaceHolder1 de la página maestra.
Al renombrar la página [WebForm1.aspx] así generada, se pueden crear las diferentes páginas que tienen [MasterPage.master] como página maestra.
Para nuestra aplicación [SimuPaie], el aspecto visual de la página maestra será el siguiente:
![]() |
N.º | Tipo | Nombre | Función |
Panel (rosa arriba) | encabezado | encabezado de la página | |
Panel (amarillo arriba) | contenido | contenido de la página | |
LinkButton | LinkButtonFaireSimulation | solicita el cálculo de la simulación | |
LinkButton | LinkButtonEffacerSimulation | borra el formulario de entrada | |
LinkButton | LinkButtonVoirSimulations | muestra la lista de simulaciones ya realizadas | |
LinkButton | LinkButtonFormulaireSimulation | vuelve al formulario de introducción de datos | |
LinkButton | LinkButtonEnregistrerSimulation | guarda la simulación actual en la lista de simulaciones | |
LinkButton | LinkButtonTerminerSession | cierra la sesión actual |
El código fuente correspondiente es el siguiente:
<%@ 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>
- línea 1: se indica el nombre de la clase de la página maestra: MasterPage
- línea 8: se define una imagen de fondo para la página.
- líneas 9-64: el formulario
- línea 10: el componente ScriptManager necesario para los efectos Ajax
- líneas 11-63: el contenedor AJax
- líneas 12-62: el contenido con Ajax
- líneas 13-55: el componente Panel [entete]
- líneas 57-60: el componente Panel [contenu]
- líneas 58-59: el componente ID [ContentPlaceHolder1] que contendrá la página encapsulada [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]
Para crear esta página, se puede insertar en el panel [entete] el código ASPX de la vista [VueEntete] de la página [Default.aspx] de la version [pam-v4-3tier-nhibernate-multivues-monopage], descrita en el apartado 8.5.2.
11.4.2. La página [Formulaire.aspx]
Para generar esta página, se seguirá el método expuesto en el apartado 11.4.1 y se renombrará como [Formulaire.aspx] la página [WebForm1.aspx] así generada. El aspecto visual de la página [Formulaire.aspx] en proceso de construcción será el siguiente:
![]() |
El aspecto visual de la página [Formulaire.aspx] tiene dos elementos:
- en [1], la página maestra con su contenedor [ContentPlaceHolder1] (2)
- en [2], los componentes colocados en el contenedor [ContentPlaceHolder1]. Estos son idénticos a los de la aplicación anterior.
El código fuente de esta página es el siguiente:
<%@ 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>
- línea 1: la directiva Page con su atributo MasterPageFile
- línea 4: la clase de control de la página maestra puede exponer campos y propiedades públicos. Estos son accesibles para las páginas encapsuladas con la sintaxis Master.[champ] o Master.[propriété]. La propiedad Master de la página designa la página maestra en forma de una instancia de tipo [System.Web.UI.MasterPage]. Por lo tanto, en nuestro ejemplo, en realidad habría que escribir (MasterPage)(Master).[champ] o (MasterPage)(Master).[propriété]. Se puede evitar este cambio de tipo insertando en la página la directiva MasterType de la línea 4. El atributo VirtualPath de esta directiva indica el archivo de la página maestra. El compilador puede entonces conocer los campos, propiedades y métodos públicos expuestos por la clase de la página maestra, en este caso de tipo [MasterPage].
- líneas 5-22: el contenido que se insertará en el contenedor [ContentPlaceHolder1] de la página maestra.
Esta página se puede construir utilizando como contenido (líneas 6-21) el de la vista [VueSaisies] descrita en el apartado 8.5.3 y el de la vista [VueSimulation] descrita en el apartado 8.5.4.
11.4.3. La página [Simulations.aspx]
Para generar esta página, se seguirá el método expuesto en el apartado 11.4.1 y se renombrará como [Simulations.aspx] la página [WebForm1.aspx] así generada. El aspecto visual de la página [Simulations.aspx] en proceso de construcción es el siguiente:
![]() |
El aspecto visual de la página [Simulations.aspx] tiene dos elementos:
- en [1], la página maestra con su contenedor [ContentPlaceHolder1]
- en [2], los componentes colocados en el contenedor [ContentPlaceHolder1]. Estos son idénticos a los de la aplicación anterior.
El código fuente de esta página es el siguiente:
<%@ 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>
Se puede construir esta página utilizando como contenido (líneas 5-21) el de la vista [VueSimulations] descrita en el apartado 8.5.5 y el de la vista [VueSimulationsVides] descrita en el apartado 8.5.6.
11.4.4. La página [Erreurs.aspx]
Para generar esta página, se seguirá el método expuesto en el apartado 11.4.1 y se renombrará como [Erreurs.aspx] la página [WebForm1.aspx] así generada. El aspecto visual de la página [Erreurs.aspx] en proceso de construcción es el siguiente:
![]() |
El aspecto visual de la página [Erreurs.aspx] tiene dos elementos:
- en [1], la página maestra con su contenedor [ContentPlaceHolder1]
- en [2], los componentes colocados en el contenedor [ContentPlaceHolder1]. Estos son idénticos a los de la aplicación anterior.
El código fuente de esta página es el siguiente:
<%@ 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. El código de control de las páginas
11.5.1. Resumen
Volvamos a la arquitectura de la aplicación:
![]() |
- [Global] es el objeto de tipo [HttpApplication] que inicializa (paso 0) la aplicación. Esta clase es idéntica a la de la anterior version.
- El código del controlador, que en la anterior version se encontraba íntegramente en [Default.aspx.cs], ahora se distribuye en varias páginas:
- [MasterPage.master]: la página maestra de las páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Contiene el menú.
- [Formulaire.aspx]: la página que presenta el formulario de simulación y gestiona las acciones que tienen lugar en dicho formulario
- [Simulations.aspx]: la página que muestra la lista de simulaciones y gestiona las acciones que tienen lugar en esta misma página
- [Erreurs.aspx]: la página que se muestra cuando se produce un error de inicialización de la aplicación. No se pueden realizar acciones en esta página.
El procesamiento de una solicitud de un cliente se lleva a cabo siguiendo los siguientes pasos:
- el cliente realiza una solicitud a la aplicación. Normalmente la realiza en una de las dos páginas [Formulaire.aspx, Simulations.aspx], pero nada le impide solicitar la página [Erreurs.aspx]. Habrá que prever este caso.
- La página solicitada procesa esta solicitud (paso 1). Para ello, puede necesitar la ayuda de la capa [métier] (paso 2), que a su vez puede necesitar la capa [dao] si es necesario intercambiar datos con la base de datos. La aplicación recibe una respuesta de la capa [métier].
- En función de esta, elige (paso 3) la vista (= la respuesta) que se enviará al cliente y le proporciona (paso 4) la información (el modelo) que necesita. Hemos visto tres posibilidades para generar esta respuesta:
- la página (D) solicitada es también la página (R) enviada como respuesta. Construir el modelo de la respuesta (R) consiste entonces en asignar a algunos de los componentes de la página (D) el valor que deben tener en la respuesta.
- la página (D) solicitada no es la página (R) enviada como respuesta. La página (D) puede entonces:
- transferir el flujo de ejecución a la página (R) mediante la instrucción Server.Transfer(" R "). La plantilla puede entonces colocarse en el contexto mediante Context.Items("clave")=valor o, más raramente, en la sesión mediante Session.Items("clave")=valor
- redirigir al cliente a la página (R) mediante la instrucción Response.redirect(" R "). A continuación, la plantilla se puede colocar en la sesión, pero no en el contexto.
- La respuesta se envía al cliente (paso 5)
Cada una de las páginas [MasterPage.master, Formulaire.aspx, Simulations.aspx, Erreurs.aspx] responderá a uno o varios de los siguientes eventos:
- Init: primer evento en el ciclo de vida de la página
- Load: se produce al cargar la página
- Click: al hacer clic en uno de los enlaces del menú de la página maestra
Procesamos las páginas una tras otra, comenzando por la página maestra.
11.5.2. Código de control de la página [MasterPage.master]
11.5.2.1. Estructura de la clase
El código de control de la página maestra tiene la estructura siguiente:
using System.Web.UI.WebControls;
namespace pam_v7
{
public partial class MasterPage : System.Web.UI.MasterPage
{
// el menú
public LinkButton OptionFaireSimulation
{
get { return LinkButtonFaireSimulation; }
}
...
// corregir el menú
public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
{
....
}
// gestión de la option [Terminer la session]
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
....
}
// inicializar página maestra
protected void Page_Init(object sender, System.EventArgs e)
{
....
}
}
}
}
- línea 5: la clase se llama [MasterPage] y deriva de la clase del sistema [System.Web.UI.MasterPage].
- líneas 9-14: las 6 opciones del menú se muestran como propiedades públicas de la clase
- líneas 16-19: el método público SetMenu permitirá a las páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] fijar el menú de la página maestra
- líneas 22-25: el procedimiento que gestionará el clic en el enlace [LinkButtonTerminerSession]
- líneas 28-31: el procedimiento de gestión del evento Init de la página maestra
11.5.2.2. Propiedades públicas de la clase
using System.Web.UI.WebControls;
namespace pam_v7
{
public partial class MasterPage : System.Web.UI.MasterPage
{
// el menú
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; }
}
...
}
}
Para entender este código, hay que recordar los componentes que forman la página maestra:
![]() |
N.º | Tipo | Nombre | Función |
Panel (rosa arriba) | encabezado | encabezado de la página | |
Panel (amarillo arriba) | contenido | contenido de la página | |
LinkButton | LinkButtonFaireSimulation | solicita el cálculo de la simulación | |
LinkButton | LinkButtonEffacerSimulation | borra el formulario de entrada | |
LinkButton | LinkButtonVoirSimulations | muestra la lista de simulaciones ya realizadas | |
LinkButton | LinkButtonFormulaireSimulation | vuelve al formulario de introducción de datos | |
LinkButton | LinkButtonEnregistrerSimulation | guarda la simulación actual en la lista de simulaciones | |
LinkButton | LinkButtonTerminerSession | cierra la sesión actual |
No se puede acceder a los componentes 1 a 6 fuera de la página que los contiene. Las propiedades de las líneas 9 a 37 tienen como objetivo hacerlos accesibles a clases externas, en este caso las clases de otras páginas de la aplicación.
11.5.2.3. El método SetMenu
El método público SetMenu permite a las páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] fijar el menú de la página maestra. Su código es básico:
// fijar el menú
public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
{
// configuramos las opciones del menú
LinkButtonFaireSimulation.Visible = boolFaireSimulation;
LinkButtonEnregistrerSimulation.Visible = boolEnregistrerSimulation;
LinkButtonEffacerSimulation.Visible = boolEffacerSimulation;
LinkButtonVoirSimulations.Visible = boolVoirSimulations;
LinkButtonFormulaireSimulation.Visible = boolFormulaireSimulation;
LinkButtonTerminerSession.Visible = boolTerminerSession;
}
11.5.2.4. Gestión de eventos de la página maestra
La página maestra gestionará dos eventos:
- el evento Init, que es el primer evento del ciclo de vida de la página
- el evento Click en el enlace [LinkButtonTerminerSession]
La página maestra tiene otros cinco enlaces: [LinkButtonFaireSimulation, LinkButtonEnregistrerSimulation, LinkButtonEffacerSimulation, LinkButtonVoirSimulations, LinkButtonFormulaireSimulation]. A modo de ejemplo, veamos qué habría que hacer al hacer clic en el enlace [LinkButtonFaireSimulation]:
- comprobar los datos introducidos (horas, días) en la página [Formulaire.aspx]
- calcular el salario
- mostrar los resultados en la página [Formulaire.aspx]
Las operaciones 1 y 3 implican tener acceso a los componentes de la página [Formulaire.aspx]. Este no es el caso. De hecho, la página maestra no tiene conocimiento alguno de los componentes de las páginas que pueden insertarse en su contenedor [ContentPlaceHolder1]. En nuestro ejemplo, es la página [Formulaire.aspx] la que debe gestionar el clic en el enlace [LinkButtonFaireSimulation], ya que es ella la que se muestra cuando se produce este evento. ¿Cómo puede ser notificada de ello?
- Dado que el enlace [LinkButtonFaireSimulation] no forma parte de la página [Formulaire.aspx], no se puede escribir en [Formulaire.aspx] el procedimiento habitual:
private void LinkButtonFaireSimulation_Click(object sender, System.EventArgs e)
{
...
}
Se puede solucionar el problema con el siguiente código en [Formulaire.aspx]:
using System.Collections.Generic;
...
namespace pam_v7
{
public partial class Formulaire : System.Web.UI.Page
{
// carga de la página
protected void Page_Load(object sender, System.EventArgs e)
{
// gestor de eventos
Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
...
}
// cálculo de la nómina
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
....
}
// borrar la simulación
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)
{
...
}
}
}
- líneas 12-15: cuando se produce el evento Load de la página [Formulaire.aspx], se ha instanciado la clase [MasterPage] de la página maestra. Sus propiedades públicas Optionxx son accesibles y son de tipo LinkButton, un componente que admite el evento Click. Asociamos a estos eventos Click los métodos:
- OptFaireSimulation_Click para el evento Click en el enlace LinkButtonFaireSimulation
- OptEffacerSimulation_Click para el evento Click en el enlace LinkButtonEffacerSimulation
- OptVoirSimulations_Click para el evento Click en el enlace LinkButtonVoirSimulations
- OptEnregistrerSimulation_Click para el evento «Haga clic en el enlace» LinkButtonEnregistrerSimulation
La gestión de los eventos al hacer clic en los seis enlaces del menú se distribuirá de la siguiente manera:
- la página [Formulaire.aspx] gestionará los enlaces [LinkButtonFaireSimulation, LinkButtonEnregistrerSimulation, LinkButtonEffacerSimulation, LinkButtonVoirSimulations]
- la página [Simulations.aspx] gestionará el enlace [LinkButtonFormulaireSimulation]
- la página maestra [MasterPage.master] gestionará el enlace [LinkButtonTerminerSession]. Para este evento, no necesita conocer la página que encapsula.
11.5.2.5. El evento Init de la página maestra
Las tres páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] de la aplicación tienen [MasterPage.master] como página maestra. Llamemos M a la página maestra y E a la página encapsulada. Cuando el cliente solicita la página E, se producen los siguientes eventos en este orden:
- E.Init
- M.Init
- E.Load
- M.Load
- ...
Vamos a utilizar el evento Init de la página M para ejecutar código que sería interesante ejecutar lo antes posible, independientemente de cuál sea la página de destino E. Para descubrir este código, repasemos la imagen general de la aplicación:
![]() |
Arriba, [Global] es el objeto de tipo [HttpApplication] que inicializa la aplicación. Esta clase es la misma que en version [pam-v4-3tier-nhibernate-multivues-monopage]:
using System;
...
namespace pam_v7
{
public class Global : System.Web.HttpApplication
{
// --- datos estáticos de la aplicación ---
public static Employe[] Employes;
public static IPamMetier PamMetier = null;
public static string Msg;
public static bool Erreur = false;
// inicio de la aplicación
public void Application_Start(object sender, EventArgs e)
{
...
}
public void Session_Start(object sender, EventArgs e)
{
...
}
}
}
Si la clase [Global] no consigue inicializar correctamente la aplicación, establece dos variables públicas estáticas:
- la variable booleana Error de la línea 12 se establece en verdadero
- la variable Msg de la línea 11 contiene un mensaje con detalles sobre el error encontrado
Cuando el usuario solicita una de las páginas [Formulaire.aspx, Simulations.aspx] y la aplicación no se ha inicializado correctamente, esta solicitud debe transferirse o redirigirse a la página [Erreurs.aspx], que mostrará el mensaje de error de la clase [Global]. Este caso se puede gestionar de diversas maneras:
- realizar la comprobación de error de inicialización en el gestor de eventos Init o Load de cada una de las páginas [Formulaire.aspx, Simulations.aspx]
- Realizar la comprobación de errores de inicialización en el controlador de eventos Init o Load de la página maestra de estas dos páginas. Este método tiene la ventaja de situar la comprobación de errores de inicialización en un único lugar.
Optamos por realizar la comprobación de error de inicialización en el controlador del evento Init de la página maestra:
protected void Page_Init(object sender, System.EventArgs e)
{
// gestor de eventos
LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
// ¿Errores de inicialización?
if (Global.Erreur)
{
// ¿Es la página encapsulada la página de errores?
bool isPageErreurs =...;
// si se muestra la página de errores, se deja tal cual; de lo contrario, se redirige al cliente a la página de errores
if (!isPageErreurs)
Response.Redirect("Erreurs.aspx");
return;
}
}
El código anterior se ejecutará tan pronto como se solicite una de las páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. En el caso de que la página solicitada sea [Formulaire.aspx, Simulations.aspx], nos limitamos (línea 12) a redirigir al cliente a la página [Erreurs.aspx], que se encarga de mostrar el mensaje de error de la clase [Global]. En el caso de que la página solicitada sea [Erreurs.aspx], esta redirección no debe tener lugar: hay que dejar que se muestre la página [Erreurs.aspx]. Por lo tanto, necesitamos saber, en el método [Page_Init] de la página maestra, qué página encapsula esta.
Volvamos al árbol de componentes de la página maestra:
...
<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>
- líneas 1-13: el contenedor de id «form1»
- líneas 4-6: el contenedor de id «entete», incluido en el contenedor de id «form1»
- líneas 8-11: el contenedor de id «contenu», incluido en el contenedor de id «form1»
- líneas 9-10: el contenedor de id «ContentPlaceHolder1», incluido en el contenedor de id «contenido»
Una página E encapsulada en la página maestra M se encuentra en el contenedor de id «ContentPlaceHolder1». Para hacer referencia a un componente de id C de esta página E, se escribirá:
this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("C");
El árbol de componentes de la página [Erreurs.aspx] es el siguiente:
<%@ 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>
Cuando la página [Erreurs.aspx] se fusiona con la página maestra M, el contenido de la etiqueta <asp:Content> anterior (líneas 5-16) se integra en la etiqueta <asp:ContentPlaceHolder> de id «ContentPlaceholder1» de la página M, con lo que el árbol de componentes de esta queda entonces así:
- línea 12: el componente [rptErreurs] puede utilizarse para saber si la página maestra M contiene o no la página [Erreurs.aspx]. De hecho, este componente solo existe en esta página.
Estas explicaciones bastan para comprender el código del procedimiento [Page_Init] de la página maestra:
protected void Page_Init(object sender, System.EventArgs e)
{
// gestor de eventos
LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
// ¿Errores de inicialización?
if (Global.Erreur)
{
// ¿Es la página encapsulada la página de errores?
bool isPageErreurs = this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("rptErreurs") != null;
// si se muestra la página de errores, se deja tal cual; de lo contrario, se redirige al cliente a la página de errores
if (!isPageErreurs)
Response.Redirect("Erreurs.aspx");
return;
}
}
- línea 4: se asocia un gestor de eventos al evento Click del enlace LinkButtonTerminerSession. Este gestor se encuentra en la clase MasterPage.
- línea 6: se comprueba si la clase [Global] ha establecido su valor booleano Error
- línea 9: si es así, el valor booleano IsPageErreurs indica si la página encapsulada en la página maestra es la página [Erreurs.aspx]
- línea 12: si la página encapsulada en la página maestra no es la página [Erreurs.aspx], entonces se redirige al cliente a esta página; de lo contrario, no se hace nada.
11.5.2.6. El evento Click en el enlace [LinkButtonTerminerSession]
![]() |
Cuando el usuario hace clic en el enlace [Terminer la session] en la vista (1) anterior, hay que vaciar el contenido de la sesión y mostrar un formulario vacío (2).
El código del gestor de este evento podría ser el siguiente:
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
// se abandona la sesión
Session.Abandon();
// se muestra la vista [formulaire]
Response.Redirect("Formulaire.aspx");
}
- línea 4: se abandona la sesión actual
- línea 6: el cliente es redirigido a la página [Formulaire.aspx]
Se observa que este código no utiliza ninguno de los componentes de las páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Por lo tanto, el evento puede ser gestionado por la propia página maestra.
11.5.3. Código de control de la página [Erreurs.aspx]
El código de control de la página [Erreurs.aspx] podría ser el siguiente:
using System.Collections.Generic;
namespace pam_v7
{
public partial class Erreurs : System.Web.UI.Page
{
protected void Page_Load(object sender, System.EventArgs e)
{
// ¿Errores de inicialización?
if (Global.Erreur)
{
// se prepara la plantilla de la página [erreurs]
List<string> erreursInitialisation = new List<string>();
erreursInitialisation.Add(Global.Msg);
// se asocia la lista de errores a su componente
rptErreurs.DataSource = erreursInitialisation;
rptErreurs.DataBind();
}
// se fija el menú
Master.SetMenu(false, false, false, false, false, false);
}
}
}
Recordemos que la página [Erreurs.aspx] tiene como única función mostrar un error de inicialización de la aplicación cuando este se produce:
- línea 10: se comprueba si la inicialización ha finalizado con un error
- líneas 13-14: si es así, el mensaje de error (Global.Msg) se coloca en una lista [ErreursInitialisation]
- líneas 16-17: se solicita al componente [rptErreurs] que muestre esta lista
- línea 20: en cualquier caso (haya error o no), no se muestran las opciones del menú de la página maestra, de modo que el usuario no puede iniciar ninguna acción nueva desde esta página.
¿Qué ocurre si el usuario solicita directamente la página [Erreurs.aspx] (algo que no se supone que haga en un uso normal de la aplicación)? Al seguir el código de [MasterPage.master.cs] y de [Erreurs.aspx.cs], se observará que:
- si se ha producido un error de inicialización, este se muestra
- si no se ha producido ningún error de inicialización, el usuario recibe una página que solo contiene el encabezado de [MasterPage.master] sin que se muestre ningún menú option.
11.5.4. Código de control de la página [Formulaire.aspx]
11.5.4.1. Estructura de la clase
El esqueleto del código de control de la página [Formulaire.aspx] podría ser el siguiente:
using Pam.Metier.Entites;
...
partial class PageFormulaire : System.Web.UI.Page
{
// carga de la página
protected void Page_Load(object sender, System.EventArgs e)
{
// gestor de eventos
Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
....
}
// cálculo de la nómina
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
....
}
// borrar la simulación
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)
{
...
}
}
El código de control de la página [Formulaire.aspx] gestiona cinco eventos:
- el evento Load de la página
- el evento Click en el enlace [LinkButtonFaireSimulation] de la página maestra
- el evento Click en el enlace [LinkButtonEffacerSimulation] de la página maestra
- el evento Click en el enlace [LinkButtonEnregistrerSimulation] de la página maestra
- El evento «Click» en el enlace [LinkButtonVoirSimulations] de la página maestra
11.5.4.2. Evento Load de la página
El esqueleto del gestor del evento Load de la página podría ser el siguiente:
protected void Page_Load(object sender, System.EventArgs e)
{
// gestor de eventos
Master.OptionFaireSimulation.Click += OptFaireSimulation_Click;
Master.OptionEffacerSimulation.Click += OptEffacerSimulation_Click;
Master.OptionVoirSimulations.Click += OptVoirSimulations_Click;
Master.OptionEnregistrerSimulation.Click += OptEnregistrerSimulation_Click;
// Visualización de vista [saisies]
...
// Posicionamiento del menú de la página maestra
...
// procesamiento de la solicitud GET
if (!IsPostBack)
{
// carga de los nombres de los empleados en el combo
...
// inicialización de la vista [saisies] con los datos introducidos memorizados en la sesión, si existen
....
}
}
Un ejemplo para aclarar el comentario de la línea 17 podría ser este:
![]() |
![]() |
- En [1], se solicita ver la lista de simulaciones. Se han realizado entradas en [A, B, C].
- En [2], se ve la lista
- en [3], se solicita volver al formulario
- en [4], se encuentra el formulario tal y como se dejó. Como ha habido dos solicitudes, (1,2) y (3,4), esto significa que:
- al pasar de [1] a [2], se guardaron los datos introducidos en [1]
- al pasar de [3] a [4], se han recuperado. Es el procedimiento [Page_Load] de [Formulaire.aspx] el que realiza esta recuperación.
Pregunta: complete el procedimiento Page_Load con la ayuda de los comentarios y el código de version [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.4.3. Gestión de eventos al hacer clic en los enlaces del menú
La estructura de los gestores de eventos de clic en los enlaces de la página maestra es la siguiente:
// cálculo de la nómina
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
// efecto Ajax
Thread.Sleep(3000);
// ¿página válida?
Page.Validate();
if (!Page.IsValid)
{
// visualización de la vista [saisie]
...
}
// la página es válida: se recuperan los datos introducidos
...
// se calcula el salario del empleado
FeuilleSalaire feuillesalaire;
try
{
feuillesalaire = ...;
}
catch (PamException ex)
{
// se ha producido un error
...
return;
}
// se guarda el resultado en la sesión
Session["simulation"] = ...;
// se guardan las entradas en la sesión
...
// visualización
...
// visualización de vistas
...
// visualización del menú MasterPage
...
}
// borrar la simulación
private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
{
// visualización del panel [saisie]
...
// selección del primer empleado
...
}
protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
{
// se introducen los datos en la sesión
...
// se muestra la vista [simulations]
Response.Redirect("simulations.aspx");
}
protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
{
// se guarda la simulación actual en la sesión del usuario
...
// se muestra la vista [simulations]
Response.Redirect("simulations.aspx");
}
Pregunta: complete el código de los procedimientos anteriores con la ayuda de los comentarios y el código de version [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.5. Código de control de la página [Simulations.aspx]
El esqueleto del código de control de la página [Simulations.aspx] podría ser el siguiente:
using System.Collections.Generic;
using Pam.Web;
using System.Web.UI.WebControls;
partial class PageSimulations : System.Web.UI.Page
{
// las simulaciones
private List<Simulation> simulations;
// carga de la página
protected void Page_Load(object sender, System.EventArgs e)
{
// gestor de eventos
Master.OptionFormulaireSimulation.Click += OptFormulaireSimulation_Click;
GridViewSimulations.RowDeleting += GridViewSimulations_RowDeleting;
// se recuperan las simulaciones de la sesión
simulations = ...;
// ¿hay simulaciones?
if (simulations.Count != 0)
{
// primera vista visible
...
// se rellena la vista de cuadrícula
...
}
else
{
// segunda vista
...
}
// se fija el menú
...
}
protected void GridViewSimulations_RowDeleting(object sender, System.Web.UI.WebControls.GridViewDeleteEventArgs e)
{
// se recuperan las simulaciones de la sesión
List<Simulation> simulations = ...;
// se elimina la simulación indicada (e.RowIndex representa el número de la línea eliminada en la vista de cuadrícula)
..
// ¿quedan simulaciones?
if (simulations.Count != 0)
{
// se rellena la vista de cuadrícula
...
}
else
{
// vista [SimulationsVides]
...
}
}
protected void OptFormulaireSimulation_Click(object sender, System.EventArgs e)
{
// se muestra la vista [formulaire]
Response.Redirect("formulaire.aspx");
}
}
Pregunta: complete el código de los procedimientos anteriores con la ayuda de los comentarios y del código de version [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.6. Código de control de la página [Default.aspx]
Se puede prever una página [Default.aspx] en la aplicación, para permitir al usuario solicitar el URL de la aplicación sin especificar una página, como se muestra a continuación:
![]() |
La solicitud [1] recibió como respuesta la página [Formulaire.aspx] (2). Sabemos que la solicitud (1) es procesada por defecto por la página [Default.aspx] de la aplicación. Para obtener (2), basta con que [Default.aspx] redirija al cliente a la página [Formulaire.aspx]. Esto se puede conseguir con el siguiente código:
partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, System.EventArgs e)
{
// se redirige al formulario de introducción de datos
Response.Redirect("Formulaire.aspx");
}
}
La página de presentación [Default.aspx] solo contiene la directiva que la vincula a [Default.aspx.cs]:
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="pam_v7._Default" Title="Untitled Page" %>






























