Skip to content

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:

  1. o cliente faz um pedido à aplicação. Faz-o numa das duas páginas [Formulaire.aspx, Simulations.aspx].
  2. 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].
  3. 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.
  4. 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

Image

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

Image

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

Image

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

Image

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

Image

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:

  1. a solicitação é feita a uma página P1 e esta gera a resposta
  2. 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:

  1. o cliente faz um pedido à página P1 (1)
  2. 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].
  3. 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.
  4. 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:

  1. o cliente faz uma solicitação à página P1 (1)
  2. 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].
  3. 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.
  4. 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
A
Painel (rosa acima)
cabeçalho
cabeçalho da página
B
Painel (amarelo acima)
conteúdo
conteúdo da página
1
LinkButton
LinkButtonFaireSimulation
solicita o cálculo da simulação
2
LinkButton
LinkButtonEffacerSimulation
limpa o formulário de introdução de dados
3
LinkButton
LinkButtonVoirSimulations
exibe a lista das simulações já realizadas
4
LinkButton
LinkButtonFormulaireSimulation
volta ao formulário de introdução de dados
5
LinkButton
LinkButtonEnregistrerSimulation
regista a simulação atual na lista de simulações
6
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>
                &nbsp;&nbsp;&nbsp</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:

  1. 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.
  2. 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].
  3. 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.
  4. 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
A
Painel (rosa acima)
cabeçalho
cabeçalho da página
B
Painel (amarelo acima)
conteúdo
conteúdo da página
1
LinkButton
LinkButtonFaireSimulation
solicita o cálculo da simulação
2
LinkButton
LinkButtonEffacerSimulation
limpa o formulário de introdução de dados
3
LinkButton
LinkButtonVoirSimulations
exibe a lista das simulações já realizadas
4
LinkButton
LinkButtonFormulaireSimulation
volta ao formulário de introdução de dados
5
LinkButton
LinkButtonEnregistrerSimulation
regista a simulação atual na lista de simulações
6
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]:

  1. verificar os dados introduzidos (horas, dias) na página [Formulaire.aspx]
  2. fazer o cálculo do salário
  3. 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:

...
<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">
              <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:ContentPlaceHolder>
            </asp:Panel>
        </div>
    </form>
</body>
</html>
  • 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.

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:

  1. o evento Load da página
  2. o evento Click no link [LinkButtonFaireSimulation] da página principal
  3. o evento Click no link [LinkButtonEffacerSimulation] da página principal
  4. o evento Click no link [LinkButtonEnregistrerSimulation] da página principal
  5. 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]


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" %>