11. A aplicação [SimuPaie] – versão 7 – ASP.NET / múltiplas visualizações / múltiplas páginas
Leituras recomendadas: referência [1], Desenvolvimento WEB com ASP.NET 1.1 parágrafo: Exemplos
Analisamos agora uma versão funcionalmente idêntica à aplicação ASP.NET de três camadas [pam-v4-3tier-nhibernate-multivues-monopage] analisada anteriormente, mas alteramos a arquitetura desta última da seguinte forma: enquanto na versão anterior as vistas eram implementadas por uma única página ASPX, aqui serão implementadas por três páginas ASPX.
A arquitetura da aplicação anterior era a seguinte:
![]() |
Temos aqui uma arquitetura MVC (Modelo – Vista – Controlador):
- [Default.aspx.cs] contém o código do controlador. A página [Default.aspx] é o único ponto de contacto com o cliente. É por ela que passam todos os pedidos do cliente.
- [Saisies, Simulation, Simulations, ...] são as vistas. Estas vistas são implementadas aqui, através de componentes [View] da página [Default.aspx].
A arquitetura da nova versão será a seguinte:
![]() |
- apenas a camada [web] sofre alterações
- as visualizações (o que é apresentado ao utilizador) não se alteram.
- O código do controlador, que na versão anterior se encontrava na íntegra em [Default.aspx.cs], está agora distribuído por várias páginas:
- [MasterPage.master]: uma página que agrupa o que é comum às diferentes vistas: a barra superior com as suas opções de menu
- [Formulaire.aspx]: a página que apresenta o formulário de simulação e gere as ações que ocorrem nesse formulário
- [Simulations.aspx]: a página que apresenta a lista de simulações e gere as ações que ocorrem nessa mesma página
- [Erreurs.aspx]: a página que é apresentada quando ocorre um erro de inicialização da aplicação. Não há ações possíveis nesta página.
Pode considerar-se que se trata aqui de uma arquitetura MVC com vários controladores, enquanto a arquitetura da versão anterior era uma arquitetura MVC com um único controlador.
O processamento de um pedido de um cliente decorre de acordo com as seguintes etapas:
- o cliente faz um pedido à aplicação. Faz-o numa das duas páginas [Formulaire.aspx, Simulations.aspx].
- A página solicitada processa essa solicitação. Para tal, pode necessitar da ajuda da camada [métier], que, por sua vez, pode necessitar da camada [dao] caso seja necessário trocar dados com a base de dados. A aplicação recebe uma resposta da camada [métier].
- Com base nessa resposta, a aplicação seleciona (3) a vista (= a resposta) a enviar ao cliente, fornecendo-lhe (4) as informações (o modelo) de que necessita.
- A resposta é enviada ao cliente (5)
11.1. As vistas da aplicação
As diferentes vistas apresentadas ao utilizador são as seguintes:
- - a vista [VueSaisies], que apresenta o formulário de simulação

- - a vista [VueSimulation], utilizada para apresentar o resultado detalhado da simulação:

- - a vista [VueSimulations], que apresenta a lista das simulações realizadas pelo cliente

- - a vista [VueSimulationsVides], que indica que o cliente não tem, ou já não tem, simulações:

- a vista [VueErreurs], que indica um erro de inicialização da aplicação:

11.2. Geração de vistas num contexto com vários controladores
Na versão anterior, todas as vistas eram geradas a partir da única página [Default.aspx]. Esta continha dois componentes [MultiView] e as vistas eram compostas pela combinação de um ou dois componentes [View] pertencentes a esses dois componentes [MultiView].
Eficaz quando há poucas vistas, esta arquitetura atinge os seus limites assim que o número de componentes que formam as diferentes vistas se torna significativo: com efeito, a cada pedido feito à única página [Default.aspx], todos os seus componentes são instanciados, embora apenas alguns deles venham a ser utilizados para gerar a resposta ao utilizador. É, assim, realizado um trabalho desnecessário a cada nova solicitação, trabalho esse que se torna oneroso quando o número total de componentes da página é elevado.
Uma solução consiste, então, em distribuir as vistas por diferentes páginas. É isso que fazemos aqui. Analisemos dois casos diferentes de geração de vistas:
- a solicitação é feita a uma página P1 e esta gera a resposta
- a solicitação é feita a uma página P1 e esta solicita a uma página P2 que gere a resposta
11.2.1. Caso 1: uma página controladora/vista
No caso 1, voltamos à arquitetura de controlador único da versão anterior, em que a página [Default.aspx] é a página P1:
![]() |
- o cliente faz um pedido à página P1 (1)
- a página P1 processa essa solicitação. Para tal, pode necessitar da ajuda da camada [métier] (2), que, por sua vez, pode necessitar da camada [dao] caso seja necessário trocar dados com a base de dados. A aplicação recebe uma resposta da camada [métier].
- Com base nessa resposta, a aplicação seleciona (3) a vista (= a resposta) a enviar ao cliente, fornecendo-lhe (4) as informações (o modelo) de que necessita. Trata-se, neste caso, de selecionar na página P1 os componentes [Panel] ou [View] a apresentar e de inicializar os componentes que estes contêm.
- A resposta é enviada ao cliente (5)
Eis dois exemplos retirados da aplicação em análise:
[page Formulaire.aspx]
![]() |
- em [1]: o utilizador, após ter solicitado a página [Formulaire.aspx], solicita uma simulação
- em [2]: a página [Formulaire.aspx] processou este pedido e gerou ela própria a resposta, exibindo um componente [View] que não tinha sido exibido em [1]
[page Simulations.aspx]
![]() |
- em [1]: o utilizador, após ter solicitado a página [Simulations.aspx], pretende remover uma simulação
- em [2]: a página [Simulations.aspx] processou este pedido e gerou ela própria a resposta, voltando a apresentar a nova lista de simulações.
2 ![]() |
11.2.2. Caso 2: uma página 1 controladora, uma página 2 controladora/visualização
O caso 2 pode abranger várias arquiteturas. Escolheremos a seguinte:
![]() |
- o cliente faz uma solicitação à página P1 (1)
- a página P1 processa essa solicitação. Para tal, pode necessitar da ajuda da camada [métier] (2), que, por sua vez, pode necessitar da camada [dao] caso seja necessário trocar dados com a base de dados. A aplicação recebe uma resposta da camada [métier].
- Com base nessa resposta, escolhe (3) a vista (= a resposta) a enviar ao cliente, fornecendo-lhe (4) as informações (o modelo) de que necessita. Acontece que, neste caso, a vista a gerar deve ser criada por uma página diferente da P1, nomeadamente a página P2. Para realizar as operações (3) e (4), a página P1 tem duas possibilidades:
- efetuar uma transferência de execução para a página P2 através da operação [Server.Transfer(" P2.aspx ")]. Neste caso, pode colocar o modelo destinado à página P2 no contexto da consulta [Context.Items[" clé "]=valeur] ou na sessão do utilizador [Session.[" clé "]=valeur]. A página P2 será então instanciada e, durante o processamento do seu evento Load, por exemplo, poderá recuperar as informações transmitidas pela página P1 através das operações [valeur=(Type)Context.Items[" clé "]] ou [valeur=(Type)Session[" clé "]], consoante o caso, em que Type é o tipo do valor associado à chave. A transmissão de valores através do contexto Context é a mais adequada se não for necessário que os valores do modelo sejam conservados para um futuro pedido do cliente.
- solicitar ao cliente que seja redirecionado para a página P2 através da operação [Response.Redirect(" P2.aspx ")]. Neste caso, a página P1 colocará o modelo destinado à página P2 na sessão, uma vez que o contexto de solicitação Context é eliminado no final de cada solicitação. No entanto, neste caso, o redirecionamento provocará o fim da primeira solicitação do cliente para P1 e o envio de uma segunda solicitação desse mesmo cliente, desta vez para P2. Há duas solicitações sucessivas. Sabemos que a sessão é uma das formas de conservar «memória» entre pedidos. Existem outras soluções além da sessão.
- Independentemente da forma como a P2 assume o controlo, voltamos depois ao caso 1: a P2 recebeu uma solicitação que irá processar (5) e irá gerar ela própria a resposta (6, 7). Também é possível imaginar que a página P2, após o processamento da solicitação, passe o controlo para uma página P3, e assim por diante.
Eis um exemplo retirado da aplicação em análise:
![]() |
- para [1]: o utilizador que solicitou a página [Formulaire.aspx] pede para ver a lista de simulações
- em [2]: a página [Formulaire.aspx] processa este pedido e redireciona o cliente para a página [Simulations.aspx]. É esta última que fornece a resposta ao utilizador. Em vez de pedir ao cliente para se redirecionar, a página [Formulaire.aspx] poderia ter encaminhado o pedido do cliente para a página [Simulations.aspx]. Nesse caso, na página [2], teria sido exibida a mesma URL que na página [1]. Com efeito, um navegador exibe sempre a última URL solicitada:
- a ação solicitada na página [1] destina-se à página [Formulaire.aspx]. O navegador efetua uma chamada para essa página através da URL POST.
- Se a página [Formulaire.aspx] processar o pedido e, em seguida, o transferir através de [Server.Transfer(" Simulations.aspx ")] para a página [Simulations.aspx], mantém-se a mesma solicitação. O navegador exibirá então, em [2], o URL de [Formulaire.aspx] para o qual ocorreu o POST.
- Se a página [Formulaire.aspx] processar o pedido e, em seguida, o redirecionar através de [Response.Redirect(" Simulations.aspx ")] para a página [Simulations.aspx], o navegador efetua então uma segunda solicitação, um GET para [Simulations.aspx]. O navegador irá então apresentar, em [2], o URL de [Simulations.aspx], para o qual foi direcionado o GET. É isso que nos mostra a captura de ecrã [2] acima.
11.3. O projeto Visual Web Developer da camada [web]
O projeto Visual Web Developer da camada [web] é o seguinte:
![]() |
- em [1] encontra-se:
- o ficheiro de configuração [Web.config] da aplicação – é idêntico ao da aplicação [pam-v4-3tier-nhibernate-multivues-monopage].
- a página [Default.aspx] – limita-se a redirecionar o cliente para a página [Formulaire.aspx]
- a página [Formulaire.aspx], que apresenta ao utilizador o formulário de simulação e processa as ações relacionadas com esse formulário
- a página [Simulations.aspx], que apresenta ao utilizador a lista das suas simulações e processa as ações relacionadas com esta página
- a página [Erreurs.aspx], que apresenta ao utilizador uma página a indicar um erro ocorrido ao iniciar a aplicação web.
- Na página [2], podem ver-se as referências do projeto.
Voltemos à arquitetura do novo projeto:
![]() |
Em relação ao projeto [pam-v4-3tier-nhibernate-multivues-monopage], apenas as vistas mudam. É assim que o novo projeto retoma alguns dos ficheiros desse projeto:
- o ficheiro de configuração [Web.config]
- os ficheiros DLL referenciados pelo [pam-dao-nhibernate, pam-metier-dao-nhibernate, Spring.Core, NHibernate]
- a classe global de aplicação [Global.asax]
- as pastas [images, ressources, pam]
Para manter a coerência com o projeto em desenvolvimento, asseguraremos que o espaço de nomes das vistas e da classe global da aplicação seja [pam-v7]:
![]() |
11.4. O código de apresentação das páginas
11.4.1. A página mestre [MasterPage.master]
As vistas da aplicação apresentadas no parágrafo 11.1 têm partes comuns que podem ser agrupadas numa página mestre, denominada «Master Page» no Visual Studio. Tomemos, por exemplo, as vistas [VueSaisies] e [VueSimulationsVides] abaixo, geradas respetivamente pelas páginas [Formulaire.aspx] e [Simulations.aspx]:
![]() |
Estas duas vistas têm em comum a barra superior (Título e Opções de menu). O mesmo se aplica a todas as vistas que serão apresentadas ao utilizador: todas terão a mesma barra superior. Para que diferentes páginas partilhem um mesmo fragmento de apresentação, existem várias soluções, entre as quais as seguintes:
- colocar esse fragmento comum num componente de utilizador. Esta era a principal técnica utilizada com o ASP.NET 1.1
- colocar esse fragmento comum numa página mestre. Esta técnica surgiu com o ASP.NET 2.0. É a que utilizamos aqui.
Para criar uma página-mestre numa aplicação web, pode-se proceder da seguinte forma:
- clique com o botão direito do rato no projeto / Adicionar um novo elemento / Página mestre:
![]() |
A adição de uma página mestre adiciona, por predefinição, três ficheiros à aplicação web:
- [MasterPage.master]: o código de apresentação da página mestre
- [MasterPage.master.cs]: o código de controlo da página mestre
- [Masterpage.Master.designer.cs]: a declaração dos componentes da página mestre
O código gerado pelo Visual Studio no ficheiro [MasterPage.master] é o seguinte:
<%@ 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>
- linha 1: a baliza <%@ Master ... %> serve para definir a página como uma página mestre. O código de controlo da página estará no ficheiro definido pelo atributo CodeBehind, e a página herdará a classe definida pelo atributo Inherits.
- linhas 12-18: o formulário da página mestre
- linhas 14-16: um contentor vazio que, na nossa aplicação, irá conter uma das páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. O cliente recebe como resposta, sempre a mesma página, a página Mestre, na qual o contentor [ContentPlaceHolder1] irá receber um fluxo HTML fornecido por uma das páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Assim, para alterar o aspeto das páginas enviadas aos clientes, basta alterar o aspeto da página mestre.
- linhas 8-9: um contentor vazio com o qual as páginas «filhas» poderão personalizar o cabeçalho <head>...</head>.
A representação visual (separador «Design») deste código-fonte é apresentada em (1) abaixo. Além disso, é possível adicionar tantos contentores quantos se desejar, graças ao componente [ContentPlaceHolder] (2) da barra de ferramentas [Standard].
![]() |
O código de controlo gerado pelo Visual Studio em [MasterPage.master.cs] é o seguinte:
using System;
public partial class MasterPage : System.Web.UI.MasterPage
{
protected void Page_Load(object sender, EventArgs e)
{
}
}
- linha 3: a classe referenciada pelo atributo [Inherits] da diretiva <%@ Master ... %> da página [MasterPage.master] deriva da classe [System.Web.UI.MasterPage]
Acima, vemos a presença do método Page_Load que gere o evento Load da página mestre. A página mestre irá conter, no seu interior, outra página. Em que ordem ocorrem os eventos Load das duas páginas? Trata-se de uma regra geral: o evento Load de um componente ocorre antes do evento do seu contentor. Neste caso, o evento Load da página inserida na página mestre ocorrerá, portanto, antes do evento da própria página mestre.
Para que gere uma página cuja página-mestre seja a página [MasterPage.master] anterior, pode-se proceder da seguinte forma:
![]() |
- em [1]: clique com o botão direito do rato na página-mestre e selecione a opção [Ajouter une page de contenu]
- em [2]: é gerada uma página por predefinição, neste caso [WebForm1.aspx].
O código de apresentação [WebForm1.aspx] é o seguinte:
<%@ 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>
- linha 1: a diretiva Page e os seus atributos
- MasterPageFile: indica o ficheiro da página-mestre da página descrita pela diretiva. O sinal ~ indica a pasta do projeto.
- os restantes parâmetros são os habituais de uma página web ASP
- linhas 2-3: as balizas <asp:Content> são associadas, uma a uma, às diretivas <asp:ContentPlaceHolder> da página-mestre através do atributo ContentPlaceHolderID. Os componentes colocados entre as linhas 2-3 acima serão, durante a execução, colocados no contentor de ID ContentPlaceHolder1 da página mestre.
Ao renomear a página [WebForm1.aspx] assim gerada, é possível criar as diferentes páginas tendo [MasterPage.master] como página mestre.
Para a nossa aplicação [SimuPaie], o aspeto visual da página-mãe será o seguinte:
![]() |
N.º | Tipo | Nome | Função |
Painel (rosa acima) | cabeçalho | cabeçalho da página | |
Painel (amarelo acima) | conteúdo | conteúdo da página | |
LinkButton | LinkButtonFaireSimulation | solicita o cálculo da simulação | |
LinkButton | LinkButtonEffacerSimulation | limpa o formulário de introdução de dados | |
LinkButton | LinkButtonVoirSimulations | exibe a lista das simulações já realizadas | |
LinkButton | LinkButtonFormulaireSimulation | volta ao formulário de introdução de dados | |
LinkButton | LinkButtonEnregistrerSimulation | regista a simulação atual na lista de simulações | |
LinkButton | LinkButtonTerminerSession | encerra a sessão atual |
O código-fonte correspondente é o seguinte:
<%@ 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>
- linha 1: repare-se no nome da classe da página-mestre: MasterPage
- linha 8: define-se uma imagem de fundo para a página.
- linhas 9-64: o formulário
- linha 10: o componente ScriptManager necessário para os efeitos Ajax
- linhas 11-63: o contentor AJax
- linhas 12-62: o conteúdo com Ajax
- linhas 13-55: o componente Panel [entete]
- linhas 57-60: o componente Panel [contenu]
- linhas 58-59: o componente ID [ContentPlaceHolder1], que conterá a página encapsulada [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]
Para construir esta página, poderá inserir-se no painel [entete], o código ASPX da vista [VueEntete] da página [Default.aspx] da versão [pam-v4-3tier-nhibernate-multivues-monopage], descrita no parágrafo 8.5.2.
11.4.2. A página [Formulaire.aspx]
Para gerar esta página, seguirá-se o método descrito no parágrafo 11.4.1 e renomear-se-á a página [WebForm1.aspx], assim gerada, para [Formulaire.aspx]. O aspeto visual da página [Formulaire.aspx] em fase de construção será o seguinte:
![]() |
O aspeto visual da página [Formulaire.aspx] tem dois elementos:
- em [1], a página principal com o seu contentor [ContentPlaceHolder1] (2)
- em [2], os componentes colocados no contentor [ContentPlaceHolder1]. Estes são idênticos aos da aplicação anterior.
O código-fonte desta página é o seguinte:
<%@ 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>
- linha 1: a diretiva Page com o seu atributo MasterPageFile
- linha 4: a classe de controlo da página mestre pode expor campos e propriedades públicos. Estes estão acessíveis às páginas encapsuladas através da sintaxe Master.[champ] ou Master.[propriété]. A propriedade Master da página designa a página mestre sob a forma de uma instância do tipo [System.Web.UI.MasterPage]. Assim, no nosso exemplo, deveria escrever-se, na realidade, (MasterPage)(Master).[champ] ou (MasterPage)(Master).[propriété]. É possível evitar esta conversão de tipo inserindo na página a diretiva MasterType da linha 4. O atributo VirtualPath desta diretiva indica o ficheiro da página-mestre. O compilador pode então identificar os campos, propriedades e métodos públicos expostos pela classe da página-mestre, neste caso do tipo [MasterPage].
- linhas 5-22: o conteúdo que será inserido no contentor [ContentPlaceHolder1] da página-mestre.
Será possível construir esta página definindo como conteúdo (linhas 6-21) o da vista [VueSaisies] descrita no parágrafo 8.5.3 e o da vista [VueSimulation] descrita no parágrafo 8.5.4.
11.4.3. A página [Simulations.aspx]
Para gerar esta página, seguirá-se o método exposto no parágrafo 11.4.1 e renomear-se-á a página [WebForm1.aspx], assim gerada, para [Simulations.aspx]. O aspeto visual da página [Simulations.aspx] em fase de construção é o seguinte:
![]() |
O aspeto visual da página [Simulations.aspx] tem dois elementos:
- em [1], a página principal com o seu contentor [ContentPlaceHolder1]
- em [2], os componentes colocados no contentor [ContentPlaceHolder1]. Estes são idênticos aos da aplicação anterior.
O código-fonte desta página é o seguinte:
<%@ 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>
É possível construir esta página inserindo como conteúdo (linhas 5-21) o da vista [VueSimulations] descrita no parágrafo 8.5.5 e o da vista [VueSimulationsVides] descrita no parágrafo 8.5.6.
11.4.4. A página [Erreurs.aspx]
Para gerar esta página, seguirá-se o método exposto no parágrafo 11.4.1 e renomear-se-á a página [WebForm1.aspx], assim gerada, para [Erreurs.aspx]. O aspeto visual da página [Erreurs.aspx] em fase de construção é o seguinte:
![]() |
O aspeto visual da página [Erreurs.aspx] tem dois elementos:
- em [1], a página principal com o seu contentor [ContentPlaceHolder1]
- em [2], os componentes colocados no contentor [ContentPlaceHolder1]. Estes são idênticos aos da aplicação anterior.
O código-fonte desta página é o seguinte:
<%@ 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. O código de controlo das páginas
11.5.1. Visão geral
Voltemos à arquitetura da aplicação:
![]() |
- [Global] é o objeto do tipo [HttpApplication] que inicializa (etapa 0) a aplicação. Esta classe é idêntica à da versão anterior.
- O código do controlador, que na versão anterior se encontrava na íntegra em [Default.aspx.cs], está agora distribuído por várias páginas:
- [MasterPage.master]: a página principal das páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. Contém o menu.
- [Formulaire.aspx]: a página que apresenta o formulário de simulação e gere as ações que ocorrem nesse formulário
- [Simulations.aspx]: a página que apresenta a lista de simulações e gere as ações que ocorrem nessa mesma página
- [Erreurs.aspx]: a página que é apresentada em caso de erro na inicialização da aplicação. Não é possível realizar quaisquer ações nesta página.
O processamento de um pedido de um cliente decorre de acordo com as seguintes etapas:
- o cliente faz um pedido à aplicação. Normalmente, faz-o numa das duas páginas [Formulaire.aspx, Simulations.aspx], mas nada o impede de solicitar a página [Erreurs.aspx]. É necessário prever este caso.
- a página solicitada processa essa solicitação (etapa 1). Para tal, pode necessitar da ajuda da camada [métier] (etapa 2), que, por sua vez, pode necessitar da camada [dao] caso seja necessário trocar dados com a base de dados. A aplicação recebe uma resposta da camada [métier].
- Com base nessa resposta, a aplicação seleciona (etapa 3) a vista (= a resposta) a enviar ao cliente e fornece-lhe (etapa 4) as informações (o modelo) de que necessita. Vimos três possibilidades para gerar esta resposta:
- a página (D) solicitada é também a página (R) enviada como resposta. Construir o modelo da resposta (R) consiste, então, em atribuir a alguns dos componentes da página (D) o valor que devem ter na resposta.
- a página (D) solicitada não é a página (R) enviada como resposta. A página (D) pode então:
- transferir o fluxo de execução para a página (R) através da instrução Server.Transfer(" R "). O modelo pode então ser colocado no contexto através de Context.Items("chave")=valor ou, mais raramente, na sessão através de Session.Items("chave")=valor
- redirecionar o cliente para a página (R) através da instrução Response.redirect(" R "). O modelo pode então ser colocado na sessão, mas não no contexto.
- A resposta é enviada ao cliente (etapa 5)
Cada uma das páginas [MasterPage.master, Formulaire.aspx, Simulations.aspx, Erreurs.aspx] responderá a um ou mais dos eventos abaixo:
- Init: primeiro evento no ciclo de vida da página
- Load: ocorre ao carregar a página
- Click: o clique num dos links do menu da página principal
Processamos as páginas uma a uma, começando pela página principal.
11.5.2. Código de controlo da página [MasterPage.master]
11.5.2.1. Estrutura da classe
O código de controlo da página principal tem a seguinte estrutura:
using System.Web.UI.WebControls;
namespace pam_v7
{
public partial class MasterPage : System.Web.UI.MasterPage
{
// o menu
public LinkButton OptionFaireSimulation
{
get { return LinkButtonFaireSimulation; }
}
...
// fixar o menu
public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
{
....
}
// gestão da opção [Terminer la session]
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
....
}
// inicializar a página principal
protected void Page_Init(object sender, System.EventArgs e)
{
....
}
}
}
}
- linha 5: a classe chama-se [MasterPage] e deriva da classe de sistema [System.Web.UI.MasterPage].
- linhas 9-14: as 6 opções do menu são apresentadas como propriedades públicas da classe
- linhas 16-19: o método público SetMenu permitirá que as páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] definam o menu da página mestre
- linhas 22-25: o procedimento que irá gerir o clique no link [LinkButtonTerminerSession]
- linhas 28-31: o procedimento de gestão do evento Init da página principal
11.5.2.2. Propriedades públicas da classe
using System.Web.UI.WebControls;
namespace pam_v7
{
public partial class MasterPage : System.Web.UI.MasterPage
{
// o menu
public LinkButton OptionFaireSimulation
{
get { return LinkButtonFaireSimulation; }
}
public LinkButton OptionEffacerSimulation
{
get { return LinkButtonEffacerSimulation; }
}
public LinkButton OptionEnregistrerSimulation
{
get { return LinkButtonEnregistrerSimulation; }
}
public LinkButton OptionVoirSimulations
{
get { return LinkButtonVoirSimulations; }
}
public LinkButton OptionTerminerSession
{
get { return LinkButtonTerminerSession; }
}
public LinkButton OptionFormulaireSimulation
{
get { return LinkButtonFormulaireSimulation; }
}
...
}
}
Para compreender este código, é necessário recordar os componentes que constituem a página mestre:
![]() |
N.º | Tipo | Nome | Função |
Painel (rosa acima) | cabeçalho | cabeçalho da página | |
Painel (amarelo acima) | conteúdo | conteúdo da página | |
LinkButton | LinkButtonFaireSimulation | solicita o cálculo da simulação | |
LinkButton | LinkButtonEffacerSimulation | limpa o formulário de introdução de dados | |
LinkButton | LinkButtonVoirSimulations | exibe a lista das simulações já realizadas | |
LinkButton | LinkButtonFormulaireSimulation | volta ao formulário de introdução de dados | |
LinkButton | LinkButtonEnregistrerSimulation | regista a simulação atual na lista de simulações | |
LinkButton | LinkButtonTerminerSession | encerra a sessão atual |
Os componentes 1 a 6 não estão acessíveis fora da página que os contém. As propriedades das linhas 9 a 37 têm como objetivo torná-los acessíveis a classes externas, neste caso, as classes das outras páginas da aplicação.
11.5.2.3. O método SetMenu
O método público SetMenu permite que as páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] definam o menu da página principal. O seu código é básico:
// fixar o menu
public void SetMenu(bool boolFaireSimulation, bool boolEnregistrerSimulation, bool boolEffacerSimulation, bool boolFormulaireSimulation, bool boolVoirSimulations, bool boolTerminerSession)
{
// definir as opções do menu
LinkButtonFaireSimulation.Visible = boolFaireSimulation;
LinkButtonEnregistrerSimulation.Visible = boolEnregistrerSimulation;
LinkButtonEffacerSimulation.Visible = boolEffacerSimulation;
LinkButtonVoirSimulations.Visible = boolVoirSimulations;
LinkButtonFormulaireSimulation.Visible = boolFormulaireSimulation;
LinkButtonTerminerSession.Visible = boolTerminerSession;
}
11.5.2.4. Gestão dos eventos da página principal
A página principal irá gerir dois eventos:
- o evento Init, que é o primeiro evento do ciclo de vida da página
- o evento Click no link [LinkButtonTerminerSession]
A página principal tem mais cinco ligações: [LinkButtonFaireSimulation, LinkButtonEnregistrerSimulation, LinkButtonEffacerSimulation, LinkButtonVoirSimulations, LinkButtonFormulaireSimulation]. A título de exemplo, vamos analisar o que seria necessário fazer ao clicar na ligação [LinkButtonFaireSimulation]:
- verificar os dados introduzidos (horas, dias) na página [Formulaire.aspx]
- fazer o cálculo do salário
- exibir os resultados na página [Formulaire.aspx]
As operações 1 e 3 implicam ter acesso aos componentes da página [Formulaire.aspx]. Não é esse o caso. Com efeito, a página principal não tem qualquer conhecimento dos componentes das páginas que possam ser inseridas no seu contentor [ContentPlaceHolder1]. No nosso exemplo, cabe à página [Formulaire.aspx] gerir o clique no link [LinkButtonFaireSimulation], uma vez que é essa página que está a ser apresentada quando ocorre esse evento. Como é que ela pode ser notificada desse evento?
- Como o link [LinkButtonFaireSimulation] não faz parte da página [Formulaire.aspx], não é possível escrever na página [Formulaire.aspx] o procedimento habitual:
private void LinkButtonFaireSimulation_Click(object sender, System.EventArgs e)
{
...
}
É possível contornar o problema com o seguinte código em [Formulaire.aspx]:
using System.Collections.Generic;
...
namespace pam_v7
{
public partial class Formulaire : System.Web.UI.Page
{
// carregamento da 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 da folha de pagamentos
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
....
}
// apagar a simulação
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)
{
...
}
}
}
- linhas 12-15: quando ocorre o evento Load da página [Formulaire.aspx], a classe [MasterPage] da página mestre já foi instanciada. As suas propriedades públicas Optionxx estão acessíveis e são do tipo LinkButton, um componente que suporta o evento Click. Associamos a estes eventos Click os métodos:
- OptFaireSimulation_Click para o evento Click no link LinkButtonFaireSimulation
- OptEffacerSimulation_Click para o evento Click no link LinkButtonEffacerSimulation
- OptVoirSimulations_Click para o evento Click no link LinkButtonVoirSimulations
- OptEnregistrerSimulation_Click para o evento Click no link LinkButtonEnregistrerSimulation
A gestão dos eventos Click nos seis links do menu será distribuída da seguinte forma:
- a página [Formulaire.aspx] irá gerir os links [LinkButtonFaireSimulation, LinkButtonEnregistrerSimulation, LinkButtonEffacerSimulation, LinkButtonVoirSimulations]
- a página [Simulations.aspx] irá gerir o link [LinkButtonFormulaireSimulation]
- a página principal [MasterPage.master] irá gerir o link [LinkButtonTerminerSession]. Para este evento, não precisa, de facto, de saber qual é a página que encapsula.
11.5.2.5. O evento Init da página principal
As três páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] da aplicação têm a [MasterPage.master] como página principal. Chamemos M à página principal e E à página encapsulada. Quando a página E é solicitada pelo cliente, ocorrem os seguintes eventos por ordem:
- E.Init
- M.Init
- E.Load
- M.Load
- ...
Vamos utilizar o evento Init da página M para executar código que seria interessante executar o mais cedo possível, independentemente da página de destino E. Para descobrir esse código, vamos rever a visão geral da aplicação:
![]() |
Acima, [Global] é o objeto do tipo [HttpApplication] que inicializa a aplicação. Esta classe é a mesma que na versão [pam-v4-3tier-nhibernate-multivues-monopage]:
using System;
...
namespace pam_v7
{
public class Global : System.Web.HttpApplication
{
// --- dados estáticos da aplicação ---
public static Employe[] Employes;
public static IPamMetier PamMetier = null;
public static string Msg;
public static bool Erreur = false;
// inicialização da aplicação
public void Application_Start(object sender, EventArgs e)
{
...
}
public void Session_Start(object sender, EventArgs e)
{
...
}
}
}
Se a classe [Global] não conseguir inicializar corretamente a aplicação, define duas variáveis públicas estáticas:
- a variável booleana Erro, na linha 12, é definida como vrai
- a variável «Msg» da linha 11 contém uma mensagem com detalhes sobre o erro ocorrido
Quando o utilizador solicita uma das páginas [Formulaire.aspx, Simulations.aspx], mas a aplicação não foi inicializada corretamente, essa solicitação deve ser transferida ou redirecionada para a página [Erreurs.aspx], que exibirá a mensagem de erro da classe [Global]. É possível gerir este caso de várias formas:
- efetuar o teste de erro de inicialização no gestor de eventos Init ou Load de cada uma das páginas [Formulaire.aspx, Simulations.aspx]
- executar o teste de erro de inicialização no gestor de eventos Init ou Load da página mestre destas duas páginas. Este método tem a vantagem de centralizar o teste de erro de inicialização num único local.
Optamos por realizar o teste de erro de inicialização no gestor de eventos Init da página mestre:
protected void Page_Init(object sender, System.EventArgs e)
{
// gestor de eventos
LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
// erros de inicialização?
if (Global.Erreur)
{
// a página encapsulada é a página de erros?
bool isPageErreurs =...;
// se for a página de erros que é apresentada, deixa-se o processo seguir o seu curso; caso contrário, redireciona-se o cliente para a página de erros
if (!isPageErreurs)
Response.Redirect("Erreurs.aspx");
return;
}
}
O código acima será executado assim que uma das páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx] for solicitada. Caso a página solicitada seja a [Formulaire.aspx, Simulations.aspx], limitamo-nos (linha 12) a redirecionar o cliente para a página [Erreurs.aspx], que se encarrega de apresentar a mensagem de erro da classe [Global]. No caso de a página solicitada ser [Erreurs.aspx], este redirecionamento não deve ocorrer: é necessário permitir que a página [Erreurs.aspx] seja apresentada. Por isso, precisamos de saber, no método [Page_Init] da página principal, qual é a página que esta encapsula.
Voltemos à árvore de componentes da página principal:
...
<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>
- linhas 1-13: o contentor com o id «form1»
- linhas 4-6: o contentor com o id «entete», incluído no contentor com o id «form1»
- linhas 8-11: o contentor com o id «contenu», incluído no contentor com o id «form1»
- linhas 9-10: o contentor com o ID «ContentPlaceHolder1», incluído no contentor com o ID «contenu»
Uma página E encapsulada na página principal M encontra-se no contentor com o ID «ContentPlaceHolder1». Para referenciar um componente com o ID C desta página E, escrever-se-á:
this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("C");
A árvore de componentes da página [Erreurs.aspx] é a seguinte:
<%@ Page Language="C#" MasterPageFile="~/MasterPage.master" AutoEventWireup="true"
CodeBehind="Erreurs.aspx.cs" Inherits="pam_v7.PageErreurs" Title="Pam : erreurs" %>
<%@ MasterType VirtualPath="~/MasterPage.master" %>
<asp:Content ID="Content1" ContentPlaceHolderID="ContentPlaceHolder1" Runat="Server">
<h3>Les erreurs suivantes se sont produites au démarrage de l'application</h3>
<ul>
<asp:Repeater id="rptErreurs" runat="server">
<ItemTemplate>
<li>
<%# Container.DataItem %>
</li>
</ItemTemplate>
</asp:Repeater>
</ul>
</asp:Content>
Quando a página [Erreurs.aspx] é combinada com a página-mãe M, o conteúdo da baliza <asp:Content> acima (linhas 5-16) é integrado na baliza <asp:ContentPlaceHolder> com o id «ContentPlaceholder1» da página M, passando a árvore de componentes desta a ficar assim:
- linha 12: o componente [rptErreurs] pode ser utilizado para determinar se a página mestre M contém ou não a página [Erreurs.aspx]. Com efeito, este componente só existe nesta página.
Estas explicações são suficientes para compreender o código do procedimento [Page_Init] da página mestre:
protected void Page_Init(object sender, System.EventArgs e)
{
// gestor de eventos
LinkButtonTerminerSession.Click += LinkButtonTerminerSession_Click;
// erros de inicialização?
if (Global.Erreur)
{
// a página encapsulada é a página de erros?
bool isPageErreurs = this.FindControl("form1").FindControl("contenu").FindControl("ContentPlaceHolder1").FindControl("rptErreurs") != null;
// se for a página de erros que for apresentada, deixa-se como está; caso contrário, redireciona-se o cliente para a página de erros
if (!isPageErreurs)
Response.Redirect("Erreurs.aspx");
return;
}
}
- linha 4: associa-se um gestor de eventos ao evento Click no link LinkButtonTerminerSession. Este gestor encontra-se na classe MasterPage.
- linha 6: verifica-se se a classe [Global] definiu o seu valor booleano Erreur
- linha 9: se sim, o valor booleano IsPageErreurs indica se a página encapsulada na página principal é a página [Erreurs.aspx]
- linha 12: se a página incorporada na página principal não for a página [Erreurs.aspx], então o cliente é redirecionado para essa página; caso contrário, não é feita qualquer ação.
11.5.2.6. O evento «Clique» no link [LinkButtonTerminerSession]
![]() |
Quando o utilizador clica no link [Terminer la session] na vista (1) acima, é necessário esvaziar o conteúdo da sessão e apresentar um formulário vazio (2).
O código do gestor deste evento poderia ser o seguinte:
protected void LinkButtonTerminerSession_Click(object sender, System.EventArgs e)
{
// encerra-se a sessão
Session.Abandon();
// exibe-se a vista [formulaire]
Response.Redirect("Formulaire.aspx");
}
- linha 4: a sessão atual é encerrada
- linha 6: o cliente é redirecionado para a página [Formulaire.aspx]
Verifica-se que este código não envolve nenhum dos componentes das páginas [Formulaire.aspx, Simulations.aspx, Erreurs.aspx]. O evento pode, portanto, ser gerido pela própria página principal.
11.5.3. Código de controlo da página [Erreurs.aspx]
O código de controlo da página [Erreurs.aspx] poderia ser o seguinte:
using System.Collections.Generic;
namespace pam_v7
{
public partial class Erreurs : System.Web.UI.Page
{
protected void Page_Load(object sender, System.EventArgs e)
{
// erros de inicialização?
if (Global.Erreur)
{
// prepara-se o modelo da página [erreurs]
List<string> erreursInitialisation = new List<string>();
erreursInitialisation.Add(Global.Msg);
// associa-se a lista de erros ao respetivo componente
rptErreurs.DataSource = erreursInitialisation;
rptErreurs.DataBind();
}
// definindo o menu
Master.SetMenu(false, false, false, false, false, false);
}
}
}
Recorde-se que a página [Erreurs.aspx] tem como única função apresentar um erro de inicialização da aplicação quando este ocorre:
- linha 10: verifica-se se a inicialização terminou com um erro
- linhas 13-14: se sim, a mensagem de erro (Global.Msg) é colocada numa lista [ErreursInitialisation]
- linhas 16-17: solicita-se ao componente [rptErreurs] que apresente essa lista
- linha 20: em todos os casos (com ou sem erro), as opções do menu da página principal não são apresentadas, pelo que o utilizador não pode iniciar nenhuma nova ação a partir desta página.
O que acontece se o utilizador aceder diretamente à página [Erreurs.aspx] (o que não é suposto acontecer numa utilização normal da aplicação)? Ao analisar o código das páginas [MasterPage.master.cs] e [Erreurs.aspx.cs], verifica-se que:
- se tiver ocorrido um erro de inicialização, este é apresentado
- se não tiver ocorrido um erro de inicialização, o utilizador recebe uma página que contém apenas o cabeçalho de [MasterPage.master], sem nenhuma opção de menu apresentada.
11.5.4. Código de controlo da página [Formulaire.aspx]
11.5.4.1. Estrutura da classe
A estrutura do código de controlo da página [Formulaire.aspx] poderia ser a seguinte:
using Pam.Metier.Entites;
...
partial class PageFormulaire : System.Web.UI.Page
{
// carregamento da 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 da folha de pagamentos
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
....
}
// apagar a simulação
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)
{
...
}
}
O código de controlo da página [Formulaire.aspx] gere cinco eventos:
- o evento Load da página
- o evento Click no link [LinkButtonFaireSimulation] da página principal
- o evento Click no link [LinkButtonEffacerSimulation] da página principal
- o evento Click no link [LinkButtonEnregistrerSimulation] da página principal
- o evento Click no link [LinkButtonVoirSimulations] da página principal
11.5.4.2. Evento «Load» da página
O esboço do gestor do evento Load da página poderia ser o seguinte:
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;
// exibição da vista [saisies]
...
// posicionamento do menu da página mestre
...
// processamento da solicitação GET
if (!IsPostBack)
{
// carregamento dos nomes dos funcionários na lista suspensa
...
// inicialização da vista [saisies] com os dados introduzidos memorizados na sessão, caso existam
....
}
}
Um exemplo para esclarecer o comentário da linha 17 poderia ser este:
![]() |
![]() |
- em [1], solicita-se a visualização da lista de simulações. Foram efetuadas entradas em [A, B, C].
- em [2], é apresentada a lista
- em [3], solicita-se o regresso ao formulário
- em [4], o formulário é apresentado tal como foi deixado. Como houve duas consultas, (1,2) e (3,4), isso significa que:
- ao passar de [1] para [2], os dados introduzidos em [1] foram guardados
- durante a transição de [3] para [4], foram recuperadas. É o procedimento [Page_Load] de [Formulaire.aspx] que efetua essa recuperação.
Pergunta: complete o procedimento Page_Load com base nos comentários e no código da versão [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.4.3. Gestão de eventos de clique nos links do menu
A estrutura dos gestores de eventos Click relativos aos links da página principal é a seguinte:
// cálculo da folha de pagamento
private void OptFaireSimulation_Click(object sender, System.EventArgs e)
{
// efeito Ajax
Thread.Sleep(3000);
// página válida?
Page.Validate();
if (!Page.IsValid)
{
// exibição da vista [saisie]
...
}
// a página é válida - recuperam-se os dados introduzidos
...
// calcula-se o salário do funcionário
FeuilleSalaire feuillesalaire;
try
{
feuillesalaire = ...;
}
catch (PamException ex)
{
// ocorreu um problema
...
return;
}
// o resultado é guardado na sessão
Session["simulation"] = ...;
// as entradas são guardadas na sessão
...
// exibição
...
// exibição de vistas
...
// exibição do menu MasterPage
...
}
// apagar a simulação
private void OptEffacerSimulation_Click(object sender, System.EventArgs e)
{
// exibição do painel [saisie]
...
// selecionar o primeiro funcionário
...
}
protected void OptVoirSimulations_Click(object sender, System.EventArgs e)
{
// inserir os dados na sessão
...
// exibir a vista [simulations]
Response.Redirect("simulations.aspx");
}
protected void OptEnregistrerSimulation_Click(object sender, System.EventArgs e)
{
// guardar a simulação atual na sessão do utilizador
...
// exibe-se a vista [simulations]
Response.Redirect("simulations.aspx");
}
Pergunta: complete o código dos procedimentos acima, com base nos comentários e no código da versão [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.5. Código de controlo da página [Simulations.aspx]
A estrutura do código de controlo da página [Simulations.aspx] poderia ser a seguinte:
using System.Collections.Generic;
using Pam.Web;
using System.Web.UI.WebControls;
partial class PageSimulations : System.Web.UI.Page
{
// as simulações
private List<Simulation> simulations;
// carregamento da página
protected void Page_Load(object sender, System.EventArgs e)
{
// gestor de eventos
Master.OptionFormulaireSimulation.Click += OptFormulaireSimulation_Click;
GridViewSimulations.RowDeleting += GridViewSimulations_RowDeleting;
// recuperam-se as simulações na sessão
simulations = ...;
// existem simulações?
if (simulations.Count != 0)
{
// primeira vista visível
...
// preenche-se o GridView
...
}
else
{
// segunda vista
...
}
// fixa-se o menu
...
}
protected void GridViewSimulations_RowDeleting(object sender, System.Web.UI.WebControls.GridViewDeleteEventArgs e)
{
// recuperam-se as simulações na sessão
List<Simulation> simulations = ...;
// elimina-se a simulação indicada (e.RowIndex representa o número da linha eliminada na GridView)
..
// Ainda existem simulações?
if (simulations.Count != 0)
{
// preenche-se a vista em grelha
...
}
else
{
// vista [SimulationsVides]
...
}
}
protected void OptFormulaireSimulation_Click(object sender, System.EventArgs e)
{
// exibe-se a vista [formulaire]
Response.Redirect("formulaire.aspx");
}
}
Pergunta: complete o código dos procedimentos acima, com base nos comentários e no código da versão [pam-v4-3tier-nhibernate-multivues-monopage]
11.5.6. Código de controlo da página [Default.aspx]
É possível prever uma página [Default.aspx] na aplicação, de modo a permitir que o utilizador solicite o URL da aplicação sem especificar uma página, como se segue:
![]() |
A solicitação [1] recebeu como resposta a página [Formulaire.aspx] (2). Sabe-se que a solicitação (1) é tratada, por predefinição, pela página [Default.aspx] da aplicação. Para obter (2), basta que a [Default.aspx] redirecione o cliente para a página [Formulaire.aspx]. Isto pode ser conseguido com o seguinte código:
partial class _Default : System.Web.UI.Page
{
protected void Page_Init(object sender, System.EventArgs e)
{
// redireciona para o formulário de introdução de dados
Response.Redirect("Formulaire.aspx");
}
}
A página de apresentação [Default.aspx] contém apenas a diretiva que a liga à [Default.aspx.cs]:
<%@ Page Language="C#" AutoEventWireup="true"
CodeBehind="Default.aspx.cs" Inherits="pam_v7._Default" Title="Untitled Page" %>

























