11. La aplicación [SimuPaie] – versión 7 – ASP.NET / múltiples vistas / múltiples páginas
Lecturas recomendadas: referencia [1], Desarrollo WEB con ASP.NET 1.1 párrafo: Ejemplos
Ahora analizaremos una versión funcionalmente idéntica a la aplicación ASP.NET de tres capas [pam-v4-3tier-nhibernate-multivues-monopage] que analizamos anteriormente, pero modificaremos la arquitectura de esta última de la siguiente manera: mientras que en la versión anterior las vistas se implementaban mediante una sola 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 punto de contacto con el cliente. Por ella pasan todas las solicitudes del cliente.
- [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 versión será la siguiente:
![]() |
- solo la capa [web] cambia
- Las vistas (lo que se muestra al usuario) no cambian.
- El código del controlador, que en la versión anterior 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 se realizan en dicho formulario
- [Simulations.aspx]: la página que muestra la lista de simulaciones y gestiona las acciones que se realizan en esa misma página
- [Erreurs.aspx]: la página que se muestra cuando ocurre un error al inicializar 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 versión anterior era una arquitectura MVC con un solo 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 en 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], la cual 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].
- Según 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 le presentan 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 con múltiples controladores
En la versión anterior, todas las vistas se generaban a partir de una ú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] que pertenecían a estos dos componentes [MultiView].
Aunque es eficaz cuando hay pocas vistas, esta arquitectura alcanza sus límites tan pronto como el número de componentes que forman las diferentes vistas se vuelve significativo: de hecho, con cada solicitud que se realiza a la única página [Default.aspx], se instancian todos sus componentes, aunque solo algunos de ellos se utilizarán para generar la respuesta al usuario. De este modo, se realiza un trabajo innecesario con cada nueva solicitud, lo cual se vuelve problemático cuando el número total de componentes de la página es elevado.
Una solución es 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
- se realiza una solicitud 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 controladora/vista
En el caso 1, volvemos a la arquitectura de un solo controlador de la versión 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), la cual 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].
- Según esta, elige (3) la vista (= la respuesta) que enviará al cliente, proporcionándole (4) la información (el modelo) que necesita. En este caso, se trata de seleccionar en la página P1 los componentes [Panel] o [View] que se mostrarán e inicializar los componentes que contienen.
- La respuesta se envía al cliente (5)
A continuación se presentan dos ejemplos tomados de la aplicación analizada:
[page Formulaire.aspx]
![]() |
- En [1]: el usuario, después de haber solicitado la página [Formulaire.aspx], solicita una simulación
- en [2]: la página [Formulaire.aspx] procesó esta solicitud y generó por sí misma la respuesta, mostrando un componente [View] que no se había mostrado en [1]
[page Simulations.aspx]
![]() |
- en [1]: el usuario, después de haber solicitado la página [Simulations.aspx], desea eliminar una simulación
- en [2]: la página [Simulations.aspx] procesó esta solicitud y generó por sí misma la respuesta, volviendo a mostrar la nueva lista de simulaciones.
2 ![]() |
11.2.2. Caso 2: una página 1 controladora, una página 2 controladora/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), la cual 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].
- Según 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 otra página que no es P1, sino la página P2. Para realizar las operaciones (3) y (4), la página P1 tiene dos opciones:
- 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, al procesar 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 Type es el tipo del valor asociado a la clave. La transmisión de valores mediante el 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á la plantilla destinada 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á que finalice la primera solicitud del cliente a P1 y que se envíe una segunda solicitud de ese mismo cliente, esta vez a P2. Hay dos solicitudes sucesivas. Sabemos que la sesión es una de las formas de conservar la «memoria» entre solicitudes. Existen otras soluciones además de la sesión.
- Independientemente de cómo P2 tome el control, luego 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.
A continuación se muestra un ejemplo tomado de la aplicación analizada:
![]() |
- a [1]: el usuario que solicitó 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 pedirle 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 ese 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á dirigida a la página [Formulaire.aspx]. El navegador realiza una solicitud a POST para acceder a esa página.
- Si la página [Formulaire.aspx] procesa la solicitud y luego la reenvía mediante [Server.Transfer(" Simulations.aspx ")] a la página [Simulations.aspx], seguimos dentro de la misma solicitud. El navegador mostrará entonces, en [2], el URL de [Formulaire.aspx] hacia el cual se realizó el POST.
- Si la página [Formulaire.aspx] procesa la solicitud y luego la redirige mediante [Response.Redirect(" Simulations.aspx ")] a 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 cual 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 de 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] – simplemente redirige al usuario a la página [Formulaire.aspx]
- la página [Formulaire.aspx], que muestra al usuario el formulario de simulación y procesa las acciones relacionadas con dicho formulario
- la página [Simulations.aspx], que muestra al usuario la lista de sus simulaciones y procesa las acciones relacionadas con esta página
- la página [Erreurs.aspx], que muestra al usuario una página que indica un error ocurrido 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 ese proyecto:
- el archivo de configuración [Web.config]
- los archivos 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 párrafo 11.1 tienen partes comunes que se pueden factorizar en una página maestra, llamada «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 le presentará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 ellas 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 derecho en el proyecto / Agregar un nuevo elemento / Página maestra:
![]() |
Al agregar 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í pues, para modificar el aspecto de las páginas enviadas a los clientes, basta con modificar 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 agregar 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]
En lo anterior, vemos la presencia del método Page_Load que maneja el evento Load de la página maestra. La página maestra contendrá en su interior otra página. ¿En qué orden ocurren los eventos Load de ambas páginas? Se trata de una regla general: el evento Load de un componente ocurre antes que el de su contenedor. En este caso, el evento Load de la página insertada en la página maestra, por lo tanto, ocurrirá antes que el de la propia página maestra.
Para que genere una página que tenga como página maestra la página anterior [MasterPage.master], se puede proceder de la siguiente manera:
![]() |
- en [1]: clic derecho en la página maestra y luego la opción [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: indica el archivo de la página maestra de la página descrita por la directiva. El signo ~ indica 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 por una a las directivas <asp:ContentPlaceHolder> de la página maestra mediante el atributo ContentPlaceHolderID. Los componentes ubicados entre las líneas 2 y 3 anteriores se colocarán, en el momento de la ejecución, dentro del 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 tengan a [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 ingreso | |
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 versión [pam-v4-3tier-nhibernate-multivues-monopage], descrita en el párrafo 8.5.2.
11.4.2. La página [Formulaire.aspx]
Para generar esta página, se seguirá el método expuesto en el párrafo 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 ubicados 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. A estos se puede acceder desde las páginas encapsuladas mediante la sintaxis Master.[champ] o Master.[propriété]. La propiedad Master de la página designa a 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 esta conversión 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. De esta manera, el compilador puede 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 párrafo 8.5.3 y el de la vista [VueSimulation] descrita en el párrafo 8.5.4.
11.4.3. La página [Simulations.aspx]
Para generar esta página, se seguirá el método expuesto en el párrafo 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 párrafo 8.5.5 y el de la vista [VueSimulationsVides] descrita en el párrafo 8.5.6.
11.4.4. La página [Erreurs.aspx]
Para generar esta página, se seguirá el método expuesto en el párrafo 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 ubicados 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. Visión general
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 versión anterior.
- El código del controlador, que en la versión anterior 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 administra las acciones que se realizan en dicho formulario
- [Simulations.aspx]: la página que muestra la lista de simulaciones y gestiona las acciones que se realizan en esta misma página
- [Erreurs.aspx]: la página que se muestra cuando se produce un error al inicializar 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), la cual 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].
- Según 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. En ese caso, la página (D) puede:
- transferir el flujo de ejecución a la página (R) mediante la instrucción Server.Transfer(" R "). La plantilla puede 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 "). El modelo puede entonces colocarse en la sesión, pero no en el contexto.
- Se envía la respuesta 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: ocurre 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; }
}
...
// corrigir el menú
public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
{
....
}
// gestión de la opción [Terminer la session]
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
....
}
// inicializar la 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 definen 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] establecer 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 ingreso | |
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 del 1 al 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] establecer 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. La 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é se debería hacer al hacer clic en el enlace [LinkButtonFaireSimulation]:
- verificar los datos ingresados (horas, días) en la página [Formulaire.aspx]
- realizar el cálculo del salario
- mostrar los resultados en la página [Formulaire.aspx]
Las operaciones 1 y 3 requieren 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 podrían insertarse en su contenedor [ContentPlaceHolder1]. En nuestro ejemplo, le corresponde a la página [Formulaire.aspx] gestionar el clic en el enlace [LinkButtonFaireSimulation], ya que es ella la que se muestra cuando ocurre 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 ocurre el evento Load de la página [Formulaire.aspx], la clase [MasterPage] de la página maestra ya ha sido instanciada. 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 Click en el enlace LinkButtonEnregistrerSimulation
La gestión de los eventos Click en los seis enlaces del menú se distribuirá de la siguiente manera:
- la página [Formulaire.aspx] administrará 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, de hecho, no necesita saber qué página 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 a [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, ocurren 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 conveniente ejecutar lo antes posible, independientemente de cuál sea la página de destino E. Para descubrir este código, revisemos la visión general de la aplicación:
![]() |
En la imagen anterior, [Global] es el objeto de tipo [HttpApplication] que inicializa la aplicación. Esta clase es la misma que en la versión [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 logra inicializar correctamente la aplicación, establece dos variables públicas estáticas:
- la variable booleana «Error» de la línea 12 se establece en vrai
- la variable «Msg» de la línea 11 contiene un mensaje con detalles sobre el error que se presentó
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], la cual mostrará el mensaje de error de la clase [Global]. Este caso se puede manejar de diversas maneras:
- realizar la comprobación de error de inicialización en el manejador de eventos Init o Load de cada una de las páginas [Formulaire.aspx, Simulations.aspx]
- Realizar la prueba de error de inicialización en el administrador de eventos Init o Load de la página maestra de estas dos páginas. Este método tiene la ventaja de ubicar la prueba de error de inicialización en un solo lugar.
Optamos por realizar la prueba de error de inicialización en el controlador de eventos Init de la página maestra:
protected void Page_Init(object sender, System.EventArgs e)
{
// gestor de eventos
LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
// ¿Hay errores de inicialización?
if (Global.Erreur)
{
// ¿La página encapsulada es la página de errores?
bool isPageErreurs =...;
// si se muestra la página de errores, se deja así; 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 cualquiera de las páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. En caso de que la página solicitada sea [Formulaire.aspx, Simulations.aspx], simplemente (línea 12) redirigimos al cliente a la página [Erreurs.aspx], la cual 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 ocurrir: hay que permitir que se muestre la página [Erreurs.aspx]. Por lo tanto, necesitamos saber, en el método [Page_Init] de la página maestra, cuál es la página que esta encapsula.
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 con id «form1»
- líneas 4-6: el contenedor con el identificador «entete», incluido en el contenedor con el identificador «form1»
- líneas 8-11: el contenedor con el id «contenu», incluido en el contenedor con el id «form1»
- líneas 9-10: el contenedor con el identificador «ContentPlaceHolder1», incluido en el contenedor con el identificador «contenu»
Una página E encapsulada en la página maestra M se encuentra dentro del contenedor con el identificador «ContentPlaceHolder1». Para hacer referencia a un componente con el identificador 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> con el identificador «ContentPlaceholder1» de la página M, por lo que el árbol de componentes de esta queda así:
- línea 12: el componente [rptErreurs] puede utilizarse para determinar 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 son suficientes para comprender el código del procedimiento [Page_Init] de la página maestra:
protected void Page_Init(object sender, System.EventArgs e)
{
// administrador de eventos
LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
// ¿Hay errores de inicialización?
if (Global.Erreur)
{
// ¿La página encapsulada es 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 así; 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 manejador de eventos al evento Click en el enlace LinkButtonTerminerSession. Este manejador se encuentra en la clase MasterPage.
- línea 6: se verifica si la clase [Global] ha establecido su valor booleano Erreur
- 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 esa página; de lo contrario, no se hace nada.
11.5.2.6. El evento de clic en el enlace [LinkButtonTerminerSession]
![]() |
Cuando el usuario hace clic en el enlace [Terminer la session] en la vista (1) anterior, se debe vaciar el contenido de la sesión y mostrar un formulario en blanco (2).
El código del controlador de este evento podría ser el siguiente:
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
// se cancela 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 manejado 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)
{
// ¿Hay 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 establece el menú
Master.SetMenu(false, false, false, false, false, false);
}
}
}
Recordemos que la única función de la página [Erreurs.aspx] es mostrar un error de inicialización de la aplicación cuando este ocurre:
- línea 10: se comprueba si la inicialización terminó 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 le pide 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é sucede si el usuario solicita directamente la página [Erreurs.aspx] (algo que no se supone que haga en el uso normal de la aplicación)? Al revisar el código de [MasterPage.master.cs] y de [Erreurs.aspx.cs], se observará que:
- si hubo un error de inicialización, este se muestra
- si no hubo un error de inicialización, el usuario recibe una página que solo contiene el encabezado de [MasterPage.master] sin ninguna opción de menú visible.
11.5.4. Código de control de la página [Formulaire.aspx]
11.5.4.1. Estructura básica 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] maneja 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 controlador 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 la vista [saisies]
...
// Posicionamiento del menú de la página maestra
...
// procesamiento de la consulta GET
if (!IsPostBack)
{
// carga de los nombres de los empleados en el menú desplegable
...
// inicialización de la vista [saisies] con los datos guardados en la sesión, si los hay
....
}
}
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 regresar al formulario
- en [4], se encuentra el formulario tal como se dejó. Como hubo dos solicitudes, (1,2) y (3,4), esto significa que:
- al pasar de [1] a [2], se guardaron los datos ingresados en [1]
- al pasar de [3] a [4], se recuperaron. Es el procedimiento [Page_Load] de [Formulaire.aspx] el que realiza esta recuperación.
Pregunta: completa el procedimiento Page_Load con la ayuda de los comentarios y el código de la versión [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.4.3. Gestión de eventos al hacer clic en los enlaces del menú
La estructura básica de los controladores de eventos Click para 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 ingresados
...
// se calcula el salario del empleado
FeuilleSalaire feuillesalaire;
try
{
feuillesalaire = ...;
}
catch (PamException ex)
{
// Se ha presentado un problema
...
return;
}
// se guarda el resultado en la sesión
Session["simulation"] = ...;
// se guardan los datos ingresados 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 guardan 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 la versión [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 llena el GridView
...
}
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 fila eliminada en el GridView)
..
// ¿Quedan simulaciones?
if (simulations.Count != 0)
{
// se llena 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: completa el código de los procedimientos anteriores con la ayuda de los comentarios y el código de la versión [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.6. Código de control de la página [Default.aspx]
Se puede incluir una página [Default.aspx] en la aplicación, para permitir que el usuario solicite 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 lograr 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 ingreso
Response.Redirect("Formulaire.aspx");
}
}
La página de presentación [Default.aspx], por su parte, solo contiene la directiva que la vincula con [Default.aspx.cs]:
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="pam_v7._Default" Title="Untitled Page" %>

























